{
  "feature_rows": [
    {
      "id": "F001",
      "area": "Backend",
      "description": "API authorization and security policies",
      "acceptance": "Sensitive APIs are role-protected, destructive actions require authorization, and bypass/admin data is not publicly exposed.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Security posture is materially below acceptance grade even though auth primitives exist. Auth exists, but multiple sensitive paths are under-protected: arbitrary organization read/update by any logged-in user, unauthenticated upload delete, and public paywall-bypass token/IP list/get/count procedures."
    },
    {
      "id": "F002",
      "area": "Backend / Users",
      "description": "User accounts: login, registration, profile, and self-management",
      "acceptance": "Users can register, sign in, recover/change credentials, and manage their own account data without support-side workarounds.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Needed for launch (duplicate/remove); Task from Anders (duplicate/remove); Task from Anders",
      "dnc_notes": "User password change: Dev: It seemed everything worked, but needs to be checked. Anders clarified that password replacement by an admin user is required, but this is unsafe...; Client: This task cannot be skipped for support reasons. On the current site an admin can change the password of a user. | Sign-up issues: Client: Very basic, obviously: No email was sent when creating a new user | User change email?: Acceptance: 1. When the user changes his email, this is actually written to the DB. 2, The change propagates everywhere it is needed. I.e. the user...",
      "notes": "Quality issues remain elsewhere, but core user-account capability is present."
    },
    {
      "id": "F003",
      "area": "Backend / CMS",
      "description": "Article CMS core: create, edit, publish, and schedule content",
      "acceptance": "Editors can create, edit, schedule, preview, and publish articles end to end from the dashboard.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Task from Anders",
      "dnc_notes": "View draft articles: Dev: Check or update api of get draft post from FE, Added permission check to view only creater posts or if admin,check or add rendering draft pages i...; Acceptance: Admin/editor/senior journalist/journalists can see unpublished posts frontend.",
      "notes": "Core authoring exists; several editorial deltas below are still incomplete."
    },
    {
      "id": "F004",
      "area": "Backend / CMS",
      "description": "Support for public article families: KBH+, city life, city spaces, city housing, opinion, visions, projects, reviews, and photo",
      "acceptance": "Accepted when the product provides support for public article families: kbh+, city life, city spaces, city housing, opinion, visions, projects, reviews, and photo in the dashboard without broken workflows.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "The families exist. Requested taxonomy/menu cleanup is a separate gap."
    },
    {
      "id": "F005",
      "area": "Backend / CMS",
      "description": "Static/basic pages CMS",
      "acceptance": "Admins can edit static pages in the CMS and the public pages render with the expected content and styling.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch (duplicate/remove); Needed for launch (discussion)",
      "dnc_notes": "Donate: Dev: On the page https://www.magasinetkbh.dk/medlem there is a \"VisaDankort / credit card\" form. On the frontend this form is already implemented, only...; Client: This task can be removed. The form is not used anymore. | Static pages column(FE): Dev: Review and assign images in the seeder. Upload sample images from the main site.; Client: These are mostly unfinished / empty, and I don't understand how they have been implemented. A discussion is needed before we lock this task.",
      "notes": "The page framework exists, but specific page surfaces can still be broken."
    },
    {
      "id": "F006",
      "area": "Comments",
      "description": "Frontend comments widget with threads and replies",
      "acceptance": "Users can read, write, and reply to comments with correct formatting and stable frontend behavior.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done); Other backlog: Mobile styling",
      "dnc_notes": "Comments don't use <p>: Dev: current site doesn't work well beacause it creates extra <p> tag with empty content. So the best way has already implemented.; Client: Best way is not implemented. Empty <p> tags is not the best solution, I agree, but instead we can just add some margin-below to <p> in the... | Comments, margin: Dev: Fix margins, deploy changes | Opinion comments, styling: Dev: add border fot he opinion and visions comments, fix background",
      "notes": "No admin moderation runtime proof was available in this pass."
    },
    {
      "id": "F007",
      "area": "Comments",
      "description": "Comment notifications and unsubscribe flow",
      "acceptance": "Commenters receive the expected notification and unsubscribe flows when comment activity affects them.",
      "status": "skipped",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Task from Anders (discussion)",
      "dnc_notes": "Rules for mailing: Dev: The estimate includes: - adding a call in the appropriate place of the email sending logic - preparing a document with texts for approval -...; Client: We can survive for now without a UI for this, but we need automated email for the same situations as on the current site: Send email after...",
      "notes": "Community retention feature from legacy appears missing. New code shows likes and CRUD, but no equivalent comment-notification or unsubscribe flow was located."
    },
    {
      "id": "F008",
      "area": "Analytics",
      "description": "Article metrics: views, shares, reactions, and GA-enriched counts",
      "acceptance": "Article statistics are collected correctly and exposed in a usable reporting surface with trustworthy counts.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Other backlog: Mobile styling",
      "dnc_notes": "Move Google Analytics: Dev: remove from the front page, add stats for dashboard post page",
      "notes": "Metrics plumbing exists, but acceptance-grade reporting and verification are incomplete. The new app stores view/share/reaction stats and can sum GA views, but dashboard reporting is limited and live proof is incomplete."
    },
    {
      "id": "F009",
      "area": "Media",
      "description": "Media library, upload workflows, and media CRUD",
      "acceptance": "Editors can upload, reuse, organize, and manage media assets without broken CRUD or deployment gaps.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "In development (almost done) (discussion)",
      "dnc_notes": "Bulk upload images: Dev: Done, but not deployed. More precisely, everything is deployed except one widget - fact.; Client: Status is a little confusing as I wrote a comment on Trello on March 13th, I assume that Nick means that these have been taken into account",
      "notes": "A separate security finding exists for unauthenticated asset deletion."
    },
    {
      "id": "F010",
      "area": "Recommender",
      "description": "Related-content or recommender system",
      "acceptance": "Each article shows genuinely related content using the intended relevance logic rather than placeholder matching.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Task from Anders",
      "dnc_notes": "Related articles: Dev: Add to the post page a list of posts with the same tags as the current post; it needs to be discussed whether posts should be added for each tag...; Client: This is a very basic part of core functionality: That \"tags\" are referenced to show the user a list of related articles. It is critical.",
      "notes": "Baseline related-content UX exists. RFQ hint toward stronger recommender behavior is unmet. New app renders related content UI blocks, but no AI or richer recommendation logic was evidenced."
    },
    {
      "id": "F011",
      "area": "Map / Geodata",
      "description": "Geocoding, geodatabase, and map-backed content",
      "acceptance": "Posts can store and use map/location data correctly, and the public map data reflects the real geodata behind the content.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "In development (almost done); Task from Anders (discussion)",
      "dnc_notes": "Location obligatory: Acceptance: As described on Trello card | Maps: Client: This is absolutely core functionality. A little map is shown on almost every post, and aggregated on the big /map page. This is critical. We...",
      "notes": "Public map surface exists. Back-office geocoding fidelity needs authenticated verification. The new app exposes a public map page, post geolocation queries, and map widgets, but explicit geocoding workflows were not fully proven."
    },
    {
      "id": "F012",
      "area": "Archive",
      "description": "Magazine archive surface and archive management",
      "acceptance": "Accepted when the live site provides magazine archive surface and archive management with correct data, routing, and styling.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "This is one of the clearest acceptance failures and also a mock/hardcode finding. New app replaces the archive with a hardcoded five-row constant that reuses the same image and PDF path while claiming all 57 issues are available."
    },
    {
      "id": "F013",
      "area": "Newsletter",
      "description": "Newsletter subscription and management",
      "acceptance": "Newsletter sign-up surfaces submit real subscriptions, hide correctly for already-subscribed users, and expose the needed management controls.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done) (duplicate/remove); Other backlog: Mobile styling",
      "dnc_notes": "Integrations page: Dev: Rewrite the auth configuration to use a shared config across both frontend and backend, so the Facebook key is taken from the config instead of...; Acceptance: It seems Mailchimp and Google ID is arelady implemented on the UI. If this is the case, we can forget this task. It is okay if the Facebook key is... | Hidden for newsletter subscribers? Sign-up block: Dev: add subscription check logic. | Newsletter modal: Dev: [FE] - adding subscription logic, restyle block [BE] - due to the second point need to check",
      "notes": "Public-facing newsletter entry point is materially fake. Generic newsletter subscribe mutation exists, popup/project widgets call it, but the dedicated newsletter page submit handler is empty and no management UI was found."
    },
    {
      "id": "F014",
      "area": "Newsletter",
      "description": "RSS feed surface",
      "acceptance": "Accepted when rss feed surface works with current-site parity and without blocking gaps.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Users still get a feed link, but the capability was not migrated into the application itself. New site only links out to an external static XML feed hosted elsewhere; no new in-app RSS generation was found."
    },
    {
      "id": "F015",
      "area": "Payments",
      "description": "Payment processing via Stripe and MobilePay",
      "acceptance": "Stripe and MobilePay payments complete reliably, access changes happen immediately, and provider sync does not leave subscribers in the wrong state.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch (discussion); Task from Anders",
      "dnc_notes": "Mobile pay: Dev: MobilePay itself is implemented, but the entire logic needs to be rechecked, since the MobilePay documentation is unclear in some places. Within...; Client: Dev comment is unclear to me, especially \"Currently, a mechanism for full synchronization of charges before any interaction with the agreement is... | Rules for Stripe: Dev: The relationship between users in our DB and users in Stripe is handled via the stripe_customer_id field, not by email. Updating the email in...; Client: When a Stripe subscriber makes changes to his name / email, this is synced with Stripe. This has not beed added as a Trello card before, as I...",
      "notes": "Core payment providers exist, but acceptance cannot treat the surrounding flow as complete. Both providers exist in the new backend, but adjacent flows remain incomplete or uneven, especially upgrade/self-service and business seat changes on MobilePay."
    },
    {
      "id": "F016",
      "area": "Payments",
      "description": "Recurring billing management and self-service subscription lifecycle",
      "acceptance": "Subscribers can upgrade, cancel, restore, and otherwise manage recurring billing without stubbed or broken self-service paths.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "The most obvious self-service upgrade path is not implemented. Cancel and restore exist, but upgrade is stubbed and UI still calls it. Portal behavior also degrades to errors or fallbacks."
    },
    {
      "id": "F017",
      "area": "Payments",
      "description": "Business users, seats, invitations, and sub-accounts",
      "acceptance": "Business subscribers can manage organizations, seats, invitations, and employee access without insecure or missing admin flows.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch (discussion); Needed for launch; In development (almost done)",
      "dnc_notes": "Organization Invitation: Dev: FE: Template, acceptance form, redirect to the page in case of unauthorized access. BE: The frontend may require additional routes to display...; Client: A discussion is needed before we lock this task. I am not sure you understand this correctly. The | Personal account page: Dev: Add a form for editing an organization. About 90% is already completed, but the MR is not merged into the main branch because the project was...; Acceptance: The page behaves as on the current site. | Subscriber management?: Dev: The admin will be given the ability to see existing subscriptions that were created via Stripe and MobilePay. The admin will also be able to...; Acceptance: 1: Admin must be able to see a complete list of all existing subscribers, showing if they subscribed with Stripe, MobilePay or are manually...",
      "notes": "This is not absent, but it is not cleanly complete enough for an unconditional acceptance. The new app does implement organization dashboards, invitations, membership lists, and seat adjustment, but the feature is uneven: seat adjustment is unsupported for MobilePay and a separate by-id organization API is insecure."
    },
    {
      "id": "F018",
      "area": "Payments",
      "description": "Webhook integration for Stripe and MobilePay",
      "acceptance": "Stripe and MobilePay webhook handling is robust enough that payment state stays synchronized even when provider callbacks are delayed.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch (discussion)",
      "dnc_notes": "Mobile pay: Dev: MobilePay itself is implemented, but the entire logic needs to be rechecked, since the MobilePay documentation is unclear in some places. Within...; Client: Dev comment is unclear to me, especially \"Currently, a mechanism for full synchronization of charges before any interaction with the agreement is...",
      "notes": "Implemented in code, but runtime confidence is lower without provider-side execution."
    },
    {
      "id": "F019",
      "area": "Data",
      "description": "Pre-launch data migration",
      "acceptance": "Accepted when pre-launch data migration works with current-site parity and without blocking gaps.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Not scored in acceptance verdict for this report. This audit did not evaluate migrated content/data parity. The new repo includes seeders and schema, but not a validated migration result. Scope note: out of scope for launch scoring."
    },
    {
      "id": "F020",
      "area": "Non-functional",
      "description": "SLA / TTLB / deployability expectations",
      "acceptance": "Accepted when sla / ttlb / deployability expectations works with current-site parity and without blocking gaps.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Deployability is better than zero, but not acceptance-clean. New app builds locally, but default test command is broken, public /annoncering returns 500 locally, and there is no evidence of SLA enforcement or performance budgets."
    },
    {
      "id": "F021",
      "area": "Dashboard",
      "description": "User management dashboard",
      "acceptance": "Accepted when the product provides user management dashboard in the dashboard without broken workflows.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Core capability exists, but dashboard integrity is inconsistent. The new app has user management surfaces, but there are duplicate dashboard implementations and at least one broken create-user link under /dashboard/admin/users/create."
    },
    {
      "id": "F022",
      "area": "Dashboard",
      "description": "Article management dashboard, writing editor, and custom widget placements",
      "acceptance": "Editors can manage articles from the dashboard, use the writing editor, and configure supported widgets without broken UI gaps.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done); Task from Anders",
      "dnc_notes": "Main image functionality: Dev: I think this can be considered completed. A separate control for editing the preview was created.; Acceptance: As described on Trello Card. It appears to be completed already, but pending a final test. | Terminology: Dev: It remains to change the modal title in the post picker.; Acceptance: 1: All labels across the admin dashboard is updated according to a list supplied by me 2: The labels will be bi-lingual Danish/English with Danish... | Set inline link target: Client: [FE] If the automatic option is a lot of work (I don't think so), then manual is okay. But we need this basic functionality. Two ways of... | View draft articles: Dev: Check or update api of get draft post from FE, Added permission check to view only creater posts or if admin,check or add rendering draft pages i...; Acceptance: Admin/editor/senior journalist/journalists can see unpublished posts frontend.",
      "notes": "Several specific widget/taxonomy deltas still fail separately below."
    },
    {
      "id": "F023",
      "area": "Dashboard",
      "description": "Reports for users, subscriptions, and business/content metrics",
      "acceptance": "Admins can review user, subscriber, and business/content metrics in a usable reporting view rather than raw or incomplete plumbing.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done); Other backlog: Mobile styling",
      "dnc_notes": "Subscriber management?: Dev: The admin will be given the ability to see existing subscriptions that were created via Stripe and MobilePay. The admin will also be able to...; Acceptance: 1: Admin must be able to see a complete list of all existing subscribers, showing if they subscribed with Stripe, MobilePay or are manually... | Move Google Analytics: Dev: remove from the front page, add stats for dashboard post page",
      "notes": "Basic counters exist. Actual reporting depth does not. New dashboard shows simple counts, but no real subscription reporting, churn reporting, or business/content metrics suite matching the RFQ wording was found."
    },
    {
      "id": "F024",
      "area": "Dashboard",
      "description": "Automated emails",
      "acceptance": "Automated emails fire for the required account, payment, business-seat, comment, and project-alert events using approved templates.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Task from Anders (discussion); Task from Anders (duplicate/remove); Task from Anders",
      "dnc_notes": "Rules for mailing: Dev: The estimate includes: - adding a call in the appropriate place of the email sending logic - preparing a document with texts for approval -...; Client: We can survive for now without a UI for this, but we need automated email for the same situations as on the current site: Send email after... | Sign-up issues: Client: Very basic, obviously: No email was sent when creating a new user | User subscription to the project: Dev: There will be a separate table and route for subscription for the backend. On the frontend, you need to add this route.; Client: Note that you have already created a box for subscribing to a project frontend.",
      "notes": "Email infrastructure exists; the promised feature breadth does not. New app sends auth and invitation emails, but no broader automated email/reporting capability matching the RFQ phrasing was located."
    },
    {
      "id": "F025",
      "area": "Dashboard",
      "description": "CSS injector or admin-controlled dynamic CSS",
      "acceptance": "Accepted when the product provides css injector or admin-controlled dynamic css in the dashboard without broken workflows.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "The narrow homepage layout toggle does not satisfy a CSS injector feature. New site only exposes a `homeLayout` switch; no generic CSS injector or equivalent admin CSS control was found."
    },
    {
      "id": "F026",
      "area": "Frontend",
      "description": "Dynamic block templates and grid-based composable front page",
      "acceptance": "Accepted when the live site provides dynamic block templates and grid-based composable front page with correct data, routing, and styling.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Composition exists and is publicly reachable."
    },
    {
      "id": "F027",
      "area": "Frontend",
      "description": "Manual front-page top-layout variant switch",
      "acceptance": "Front-page layout variants and featured-image controls can be switched intentionally and the change is reflected correctly on the site.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done)",
      "dnc_notes": "Main image functionality: Dev: I think this can be considered completed. A separate control for editing the preview was created.; Acceptance: As described on Trello Card. It appears to be completed already, but pending a final test. | Opinion Author Photo: Dev: The backend is ready, it remains to use the values on the frontend.; Acceptance: 1. There must be a switch on the dashboard where admin/journalist etc. can choose to show the main image on the front page and the opinion cover...",
      "notes": "Likely functionally present, but the operational UX requirement is unproven. New homepage supports `default` and `compact` layouts via site config, but the spec asked for very easy main-menu access and that UX was not verified."
    },
    {
      "id": "F028",
      "area": "Frontend / Map",
      "description": "Map page and map widget",
      "acceptance": "The public map page and inline map widget both render correct data and link back to the mapped content as expected.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Task from Anders (discussion); Other backlog: Mobile styling",
      "dnc_notes": "Maps: Client: This is absolutely core functionality. A little map is shown on almost every post, and aggregated on the big /map page. This is critical. We... | Is /kort working?: Dev: it works.",
      "notes": "Deeper interactive map QA was outside this pass."
    },
    {
      "id": "F029",
      "area": "Frontend / Sections",
      "description": "City spaces, city life, and city housing list/detail pages",
      "acceptance": "Accepted when the live site provides city spaces, city life, and city housing list/detail pages with correct data, routing, and styling.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Routing defect is covered separately under root-slug migration."
    },
    {
      "id": "F030",
      "area": "Frontend / Sections",
      "description": "Opinion list and detail pages",
      "acceptance": "Opinion pages render correctly, including their specific author/presentation rules, on list and detail views.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done) (duplicate/remove); Task from Anders",
      "dnc_notes": "Opinion section: Dev: points to fix described on the first comment; Acceptance: This is a duplicate of task 4 above so can be removed | Name of opinoin writer: Client: [FE] add new field for the opinion articles type (1-2h) [BE] - Add field for post table 1-3h(change DTO, service type and table structure in DB)",
      "notes": "New app implements opinion list and detail routes."
    },
    {
      "id": "F031",
      "area": "Frontend / Sections",
      "description": "Visions list and detail pages",
      "acceptance": "Visions pages render the right content, labels, widgets, and styling on both list and detail views.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Task from Anders; Other backlog: Mobile styling",
      "dnc_notes": "Visions, tasks: Client: [FE] - show visioner label, improve logic for most read, most popular, change widget text (2h) [BE] - need to check some points and logic for... | Captions on Visioner: Dev: fix caption styles | Visioner cover: Dev: added all style improves",
      "notes": "New app implements visions list/detail routes and renders vote-related stats."
    },
    {
      "id": "F032",
      "area": "Frontend / Sections",
      "description": "Projects list and detail pages",
      "acceptance": "Accepted when the live site provides projects list and detail pages with correct data, routing, and styling.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Project alerting is a separate missing sub-capability."
    },
    {
      "id": "F033",
      "area": "Frontend / Sections",
      "description": "Reviews list and detail pages",
      "acceptance": "Reviews pages render the correct review content and metadata instead of mixing in the wrong section data.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done); Other backlog: Mobile styling",
      "dnc_notes": "Wrong content shown in section: Dev: improve logic for fetching reviews by passing type; Acceptance: As described on Trello card on 19th March 2026 | Anmeldelser (reviews): Dev: [FE] - fix line height for titles (1h) [BE] - need to check points 1 and 2",
      "notes": "New app implements review list/detail routes and review metadata fields."
    },
    {
      "id": "F034",
      "area": "Frontend / Sections",
      "description": "Photo list and detail pages",
      "acceptance": "Photo stories support the expected multi-image content flow and remain readable/styled correctly on the live site.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Task from Anders (discussion)",
      "dnc_notes": "Content type (Photo): Client: Maybe this is a 0 hour job? I asked a question on the task on Februay 23rd but have never received a reply. Actually, images added by choosing it...",
      "notes": "New app implements photo list/detail routes and photo media rendering."
    },
    {
      "id": "F035",
      "area": "Frontend / Commerce",
      "description": "Personal subscription purchase flow",
      "acceptance": "Personal subscription entry points show the right offers and CTAs, hide when inappropriate, and do not expose obsolete purchase UI.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Needed for launch (duplicate/remove); Other backlog: Mobile styling",
      "dnc_notes": "Donate: Dev: On the page https://www.magasinetkbh.dk/medlem there is a \"VisaDankort / credit card\" form. On the frontend this form is already implemented, only...; Client: This task can be removed. The form is not used anymore. | Hidden for subscribers?: Dev: adding this logic from previous block | Hide \"become member\" for journalists etc.: Dev: adding logic hide member banner",
      "notes": "Core flow exists, but acceptance cannot treat it as fully delivered. New app has personal pricing and checkout pages, but surrounding lifecycle is incomplete and the landing page still carries hardcoded marketing values."
    },
    {
      "id": "F036",
      "area": "Frontend / Commerce",
      "description": "Business subscription purchase flow",
      "acceptance": "Business subscription purchase and invite flows work for master and employee subscribers from invite through access grant.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch (discussion)",
      "dnc_notes": "Organization Invitation: Dev: FE: Template, acceptance form, redirect to the page in case of unauthorized access. BE: The frontend may require additional routes to display...; Client: A discussion is needed before we lock this task. I am not sure you understand this correctly. The",
      "notes": "Good amount of code exists, but not enough to call the overall business flow fully accepted. New app has business pricing and checkout scaffolding plus organization dashboard flows, but some provider paths and later management actions are incomplete."
    },
    {
      "id": "F037",
      "area": "Frontend / Commercial",
      "description": "Advertiser promo surface",
      "acceptance": "Accepted when the live site provides advertiser promo surface with correct data, routing, and styling.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Public commercial entry point is currently broken at runtime. New app has an advertising page route, but it crashes locally with a server-side 500."
    },
    {
      "id": "F038",
      "area": "Frontend / Commercial",
      "description": "Sponsor promo surface",
      "acceptance": "Accepted when the live site provides sponsor promo surface with correct data, routing, and styling.",
      "status": "partial",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Usable as a brochure page, not as a fully modernized flow. New app ships a sponsorship page, sponsor plan CRUD, and sponsor listing, but conversion still relies on mailto/manual contact and legacy assets."
    },
    {
      "id": "F039",
      "area": "Frontend / Profile",
      "description": "User profile and subscription self-management",
      "acceptance": "The profile/account area lets users manage their details, organization context, subscription details, and related profile surfaces safely.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch; Task from Anders; Other backlog: Mobile styling (discussion)",
      "dnc_notes": "Personal account page: Dev: Add a form for editing an organization. About 90% is already completed, but the MR is not merged into the main branch because the project was...; Acceptance: The page behaves as on the current site. | User change email?: Acceptance: 1. When the user changes his email, this is actually written to the DB. 2, The change propagates everywhere it is needed. I.e. the user... | /profile: Dev: [FE] - recheck all styles and logic, could propose just to max height for comment section, it will be quick fix, if not - need be help [BE] - for...",
      "notes": "Subscription upgrade remains incomplete, but the broader profile surface exists."
    },
    {
      "id": "F040",
      "area": "Frontend / Taxonomy",
      "description": "Author, district, and tag index pages",
      "acceptance": "Author, district, and tag pages exist with correct routing/data so users can actually browse those taxonomy surfaces.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "In development (almost done) (discussion); Other backlog: Mobile styling",
      "dnc_notes": "The \"Author\": Dev: The functionality is ready, a few bugs need to be fixed.; Acceptance: As described and discussed on Trello Card, including my comments from March 19th. More pecise acceptance criteria is difficult, as communication... | Journalist page: Dev: [FE] - adding new view for this page (4-5h) [BE] - need to add functionality for the dashboard for managing all fields",
      "notes": "Route infrastructure is present; author-page confidence is lower without seeded author data. District and tag routes clearly exist and render. Author route exists in code, but live proof was limited because seeded author data was sparse."
    },
    {
      "id": "F041",
      "area": "Paywall",
      "description": "SEO-friendly paywall and gated KBH+ behavior",
      "acceptance": "KBH+ and paywall gating behave correctly for each user state without unsafe access shortcuts or broken control surfaces.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done)",
      "dnc_notes": "Set paywall access?: Dev: This task was apparently done by Vadym and is almost completed.; Acceptance: As described on Trello Card, including the 4 last points written by me on March 19th",
      "notes": "Feature exists, but the control surface is not safely implemented. New app has KBH+ gating and subscription checks, but paywall bypass exposure and guest-link weaknesses materially undermine the implementation."
    },
    {
      "id": "F042",
      "area": "Widgets",
      "description": "Inline timeline widget",
      "acceptance": "Accepted when editors can configure inline timeline widget and the frontend rendering matches the intended design and behavior.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "The new editor stores title, description, timeline items, icon, media, and text, matching the requested shape."
    },
    {
      "id": "F043",
      "area": "Widgets",
      "description": "Inline chart widget with editorial data entry",
      "acceptance": "Accepted when editors can configure inline chart widget with editorial data entry and the frontend rendering matches the intended design and behavior.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Existing chart components are tied to poll result rendering, not a generic inline chart authoring feature. The new editor exposes poll, vote, suggestion, timeline, map, etc., but no generic chart widget type or chart-data-entry workflow was found."
    },
    {
      "id": "F044",
      "area": "Widgets",
      "description": "Inline poll widget with multiple choice, checkboxes, slider, and free text",
      "acceptance": "Editors can configure polls and visitors can use all supported answer types without the widget breaking.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Task from Anders (discussion)",
      "dnc_notes": "Polls (not working): Client: Not critical as such, but it's already implemented, just buggy, and we should fix it before launch [FE] - polls are working, client have bugs...",
      "notes": "The editor and poll model support radio, checkbox, slider, and textarea question types."
    },
    {
      "id": "F045",
      "area": "Widgets",
      "description": "Inline CityChange single-suggestion widget with ID field and address override",
      "acceptance": "Editors can place the CityChange single-suggestion widget with the expected ID-driven behavior and any promised override fields.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Other backlog: Mobile styling",
      "dnc_notes": "CityChange inline widget: Dev: fixed error (I think it related to passed suggestion id or address)",
      "notes": "Withdrawn from pass/fail scoring because the spec later deletes this as net-new scope. The editor supports a suggestion ID and variant, but no address-override field exists. Scope note: withdrawn from pass/fail scoring."
    },
    {
      "id": "F046",
      "area": "Widgets",
      "description": "Before/after slider 1px white split stroke",
      "acceptance": "The before/after slider renders and behaves as designed, including the required split-line presentation.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "won't-do",
      "dnc_status": "In development (almost done) (duplicate/remove)",
      "dnc_notes": "Before / After slider: Dev: No longer актуально, the interface changed during \"Bulk upload images\" implementation.; Acceptance: Seems to be fixed so we can forget",
      "notes": "The slider renders a white split line (`w-1 bg-white`) and draggable handle."
    },
    {
      "id": "F047",
      "area": "Editorial taxonomy",
      "description": "Global tag replace / merge workflow",
      "acceptance": "Editors can replace or merge tags globally without manual article-by-article cleanup.",
      "status": "skipped",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Task from Anders",
      "dnc_notes": "Tags issues: Dev: I think something like this can be implemented: \"merge tags\" - create one tag from several tags \"copy tag\" - when creating a new tag, it will...; Client: The \"tag replacement\" part of the task is not critical. But item 3 mentioned on the task is necessary. It's not critica, but I don't want to...",
      "notes": "New tag CRUD exists, but no tag replace/merge flow across articles was found."
    },
    {
      "id": "F048",
      "area": "Editorial taxonomy",
      "description": "Improved multi-tag add UX",
      "acceptance": "Tag-selection UX supports repeated add/remove work cleanly, including obvious deselect behavior.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Task from Anders",
      "dnc_notes": "Basic deselect: Dev: If click in select to selected value it is unselect; Client: If in select secondaty click on select it it is unselect",
      "notes": "Selected tags are maintained separately from search results and the picker clears search state on close, matching the intended flow substantially better than legacy."
    },
    {
      "id": "F049",
      "area": "Editorial model",
      "description": "Reworked article-type taxonomy and creation menu",
      "acceptance": "The editorial content-type model and creation menu reflect the intended taxonomy and not just a flattened approximation.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch (discussion); In development (almost done)",
      "dnc_notes": "\"Project\" content type: Dev: Only the post picker needs to be fixed here, include projects, and change the field order.; Client: A discussion is needed before we lock this task. I am not sure you understand this correctly. This is an automated proces and it should work like... | Terminology: Dev: It remains to change the modal title in the post picker.; Acceptance: 1: All labels across the admin dashboard is updated according to a list supplied by me 2: The labels will be bi-lingual Danish/English with Danish...",
      "notes": "The platform supports the public families, but not the requested editorial creation model. New app still exposes a flat topic enum. Several requested distinctions such as Standard-with-review, sponsored as type, and richer hierarchy/menu semantics are not present as specified."
    },
    {
      "id": "F050",
      "area": "Editorial model",
      "description": "Primary topic tag behavior with frontend display and quote icon for 'kommentar'",
      "acceptance": "Primary-topic rendering behaves correctly on the frontend, including the special kommentar treatment and quote/label behavior.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Other backlog: Mobile styling",
      "dnc_notes": "\" before primary topic: Dev: Implemented if you chose/create 'kommentar' tag in the \"Primary tag\" field in the dashboard, but probubbly need to change quote icon | Topics are suddenly not all-caps: Dev: added \"uppercase\" class for all topics (could be removed when changed underline animations)",
      "notes": "Primary tag exists in the editor, renders on frontend, links to tag pages, and adds a quote icon when the tag name is `kommentar`."
    },
    {
      "id": "F051",
      "area": "Editorial UX",
      "description": "Special-character shortcut buttons in editor for em-dash and guillemets",
      "acceptance": "Accepted when the product provides special-character shortcut buttons in editor for em-dash and guillemets in the dashboard without broken workflows.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Toolbar buttons exist for formatting, alignment, lists, links, etc., but no explicit shortcut buttons for `—`, `»`, or `«` were found."
    },
    {
      "id": "F052",
      "area": "Routing / SEO",
      "description": "Root-slug article URLs plus redirects from old article paths",
      "acceptance": "Public URLs match the legacy structure, old paths redirect correctly, and the SEO basics around discovery surfaces are in place.",
      "status": "skipped",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Needed for launch; Needed for launch (discussion); In development (almost done) (discussion)",
      "dnc_notes": "SiteMap.xml: Dev: Here it is required to add logic for generating sitemap.xml.; Acceptance: A correct sitemap file on the site | URL structure (FE): Dev: SEO requires preserving the URL structure. Accordingly, the following page components need to be migrated: /kbh+, /byens-rum, /byens-liv...; Acceptance: The URL structure on the new site is exactly the same as on the existing site. (I don't understand why the URL structure was changed in the first... | robots.txt: Dev: Add a text field on the settings page. Route /robots.txt returns the content stored in the database.; Acceptance: Admin has access to a text field for entering the content of the robots.txt file. The content of this field is the content for the robots.txt file. | Danish characters in slug: Dev: Done.; Client: This is not done. Tested on 16.4.26",
      "notes": "This is both a spec miss and a migration/SEO miss. New app still routes many article families under `/inhold/${slug}` instead of root slugs, and no redirect implementation for the old scheme was found."
    },
    {
      "id": "F053",
      "area": "Editorial media",
      "description": "Bulk-fill photographer and ALT fields for inline images",
      "acceptance": "Accepted when the product provides bulk-fill photographer and alt fields for inline images in the dashboard without broken workflows.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "New app lets editors edit alt/caption/author per image, but no one-shot bulk-populate action for all selected images was found."
    },
    {
      "id": "F054",
      "area": "Editorial media",
      "description": "Thumbnail-based inline-image placement in the editor",
      "acceptance": "Accepted when the product provides thumbnail-based inline-image placement in the editor in the dashboard without broken workflows.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "New editor renders selected images as visible previews/thumbnails inside the node UI."
    },
    {
      "id": "F055",
      "area": "Editorial media",
      "description": "Drag-and-drop reordering of inline-image placeholders",
      "acceptance": "Accepted when the product provides drag-and-drop reordering of inline-image placeholders in the dashboard without broken workflows.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Kept in appendix scoring only; does not drive refund on its own. No drag-and-drop ordering UI for inline-image placeholders was found in the modal or node. Scope note: optional item."
    },
    {
      "id": "F056",
      "area": "Editorial media",
      "description": "Edit inline-image captions directly from the thumbnail UI",
      "acceptance": "Editors can adjust inline-image caption data from the image UI and the frontend renders those captions cleanly.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Task from Anders (discussion); Other backlog: Mobile styling",
      "dnc_notes": "Captions connected to images: Dev: Here, a MediaCollection will be added to the post edit page to allow setting caption and author values for each media item, which will be attached...; Client: Scope is unclear here as I am unsure of the options. We need to discuss this. As far as I understood, already fixed due this tasks... | Inline captions are now messed up: Dev: We have a problem with this task due to the design system and logic: if we have full width image caption has been located on the left side....",
      "notes": "Optional item; implemented. Scope note: optional item."
    },
    {
      "id": "F057",
      "area": "Editorial UX",
      "description": "Pre-populate writer/byline from the creating user",
      "acceptance": "Accepted when the product provides pre-populate writer/byline from the creating user in the dashboard without broken workflows.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "New post defaults `authorId` to the main profile of the creating user while keeping the field editable."
    },
    {
      "id": "F058",
      "area": "Search",
      "description": "AND semantics for multi-term search",
      "acceptance": "Search matches actual post content and uses AND semantics for multi-term queries.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "Task from Anders",
      "dnc_notes": "Search not working: Dev: A content_text field will be added, where the text version of the content field will be stored to enable search.; Client: We can't launch a site with a search function that doesn't actually work.",
      "notes": "Feature exists, but the required semantic change does not. New search repository still uses `or(ilike(title), ilike(description))`, so the requested AND semantics were not implemented."
    },
    {
      "id": "F059",
      "area": "Design system",
      "description": "Reuse Caecilia and Montserrat fonts from the old site",
      "acceptance": "Accepted when reuse caecilia and montserrat fonts from the old site works with current-site parity and without blocking gaps.",
      "status": "full",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "New app imports local Caecilia files and Montserrat via next/font, and editor font controls expose both."
    },
    {
      "id": "F060",
      "area": "Design system",
      "description": "Use additional 'Publish' title font pre-launch",
      "acceptance": "Accepted when use additional 'publish' title font pre-launch works with current-site parity and without blocking gaps.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "Withdrawn requirement; excluded from pass/fail scoring. The same spec explicitly marks this as removed. Scope note: withdrawn from pass/fail scoring."
    },
    {
      "id": "F061",
      "area": "CityChange",
      "description": "Deep links from CityChange suggestions into the app",
      "acceptance": "CityChange suggestions generate the intended deep links so users land in the app correctly from the site.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done)",
      "dnc_notes": "CityChange page?: Dev: works but need someone to check from the backend side; Client: It seems the suggestions shown on the page is pulled from some test DB. I don't know. It's not the data from the actual DB (at least, I don't hope so)",
      "notes": "The existing location-based suggestion widget now builds the requested `citychange.page.link` deep links per suggestion ID."
    },
    {
      "id": "F062",
      "area": "Paywall",
      "description": "Guest/share links that bypass the paywall",
      "acceptance": "Guest/share links bypass the paywall only in the controlled ways specified, with working generation and safe invalidation behavior.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done)",
      "dnc_notes": "Set paywall access?: Dev: This task was apparently done by Vadym and is almost completed.; Acceptance: As described on Trello Card, including the 4 last points written by me on March 19th",
      "notes": "Feature exists in reduced and unsafe form. New app can mint tokens with optional expiry, but it does not implement one-time invalidation, list/edit UI is broken, and URL generation is wrong for `/inhold/*` content."
    },
    {
      "id": "F063",
      "area": "Profile",
      "description": "Profile page list of the user's comments with deep link and reply marker",
      "acceptance": "The profile page shows the user's comments with working deep links and clear reply markers.",
      "status": "full",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Other backlog: Mobile styling (discussion)",
      "dnc_notes": "/profile: Dev: [FE] - recheck all styles and logic, could propose just to max height for comment section, it will be quick fix, if not - need be help [BE] - for...",
      "notes": "New profile comments block lists user comments, marks replies, and links to the specific comment highlight on the article page."
    },
    {
      "id": "F064",
      "area": "Payments",
      "description": "Admin control to pause all subscriber payments while preserving access",
      "acceptance": "Accepted when admin control to pause all subscriber payments while preserving access works end to end and keeps billing/access state synchronized without manual repair.",
      "status": "skipped",
      "dnc_signal": "Not mentioned by DnC",
      "dnc_sentiment": "",
      "dnc_status": "Not mentioned by DnC",
      "dnc_notes": "",
      "notes": "No pause-all-subscriber control, service, or admin surface matching this requirement was found."
    },
    {
      "id": "F065",
      "area": "Projects",
      "description": "Project-specific update alerts / email notifications",
      "acceptance": "Users can subscribe to project updates, receive the right one-time publish alerts, and unsubscribe cleanly.",
      "status": "skipped",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "blocked",
      "dnc_status": "Task from Anders (discussion); Task from Anders",
      "dnc_notes": "Rules for mailing: Dev: The estimate includes: - adding a call in the appropriate place of the email sending logic - preparing a document with texts for approval -...; Client: We can survive for now without a UI for this, but we need automated email for the same situations as on the current site: Send email after... | User subscription to the project: Dev: There will be a separate table and route for subscription for the backend. On the frontend, you need to add this route.; Client: Note that you have already created a box for subscribing to a project frontend.",
      "notes": "This is a deceptive mismatch between copy and implementation. The new CTA text promises project-specific alerts, but the handler only subscribes the email to the generic newsletter list and sends no project context."
    },
    {
      "id": "F066",
      "area": "Dashboard",
      "description": "Paywall-bypass admin UI integrity",
      "acceptance": "Paywall-bypass admin tools let staff manage tokens/IPs without broken fields, missing edit routes, or unsafe data exposure.",
      "status": "partial",
      "dnc_signal": "Mentioned in DnC",
      "dnc_sentiment": "working",
      "dnc_status": "In development (almost done)",
      "dnc_notes": "Set paywall access?: Dev: This task was apparently done by Vadym and is almost completed.; Acceptance: As described on Trello Card, including the 4 last points written by me on March 19th",
      "notes": "Admin tooling exists but is internally broken. New app has token and IP list UIs, but token edit routes are missing and the token editor binds `expireAt` instead of `expiresAt`."
    }
  ],
  "code_review_rows": [
    {
      "id": "A001",
      "source": "Audit Findings",
      "category": "Security",
      "title": "Tracked secrets and third-party credentials are committed in `.env.example`",
      "severity_1_10": 10,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Repo-wide",
      "evidence": ".env.example:29-30, 38-39, 62-63, 75-87, 106-107 include real-looking Better Auth, SMTP host, Google, Facebook, Stripe, and MobilePay credentials.",
      "impact": "This is direct credential exposure in a deliverable repository. Even if some keys are test-only, it normalizes unsafe handling and exposes integration surface details that do not belong in versioned examples.",
      "recommendation": "Rotate every exposed secret, purge them from history if possible, and replace the example file with placeholders only."
    },
    {
      "id": "A002",
      "source": "Audit Findings",
      "category": "Security",
      "title": "Paywall-bypass tokens and bypass IPs are publicly enumerable through tRPC",
      "severity_1_10": 10,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Set paywall access? [In development (almost done)]",
      "surface_or_reachability": "Reachable to any client that can call public procedures",
      "evidence": "src/server/modules/paywall-bypass/paywall-bypass-token.router.ts:28-48 and paywall-bypass-ip.router.ts:28-48 expose get/list/count as `publicProcedure`; corresponding services at token.service.ts:66-84 and ip.service.ts:61-79 do not authorize access.",
      "impact": "This turns paywall exception data into public metadata. It undermines the access-control model and exposes operational bypass mechanisms that should be tightly restricted.",
      "recommendation": "Change list/get/count to protected admin-only procedures and enforce gate authorization in the service layer."
    },
    {
      "id": "A003",
      "source": "Audit Findings",
      "category": "Security",
      "title": "Any authenticated user can read and update arbitrary organizations by ID",
      "severity_1_10": 10,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Organization Invitation [Needed for launch]; Personal account page [Needed for launch]; Subscriber management? [In development (almost done)]",
      "surface_or_reachability": "Reachable to any logged-in user",
      "evidence": "src/app/api/organization/[id]/route.ts:8-50 performs only a session check before returning org data; PUT at lines 68-122 updates by raw organization ID with no membership or role check.",
      "impact": "This is a read/write insecure direct object reference on organization data. It exposes and allows modification of another organization's profile details with nothing more than a valid session.",
      "recommendation": "Require membership/role checks before GET and PUT, and route these operations through a single authorized service instead of raw table access."
    },
    {
      "id": "A014",
      "source": "Audit Findings",
      "category": "Ops / Data safety",
      "title": "Default `pnpm db:seed` command is destructive demo seeding, not production bootstrap",
      "severity_1_10": 10,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Repo-wide",
      "evidence": "package.json:24 exposes `db:seed`; src/server/commands/db-seed.command.ts:35-95 starts by calling clearAllSeeder; src/lib/database/seeders/clear-all-seeder.ts:14-26 deletes existing comments, tags, memberships, invitations, and organizations before the script creates demo users/content.",
      "impact": "This is a release blocker because the repo's primary seed command is unsafe on a real environment and mixes destructive wipes with demo fixture creation. Running the wrong documented bootstrap step can destroy data and pollute production with test content.",
      "recommendation": "Split seeding into clearly named commands: a non-destructive, idempotent production bootstrap for required system records, and a separate demo/dev seed. Hard-fail the demo seed in production environments."
    },
    {
      "id": "M001",
      "source": "Mock Findings",
      "category": "Mock / hardcoded data",
      "title": "Archive page",
      "severity_1_10": 10,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Archive page",
      "evidence": "src/app/(main)/arkiv/page.tsx:19-99 defines a fixed `items` array with five records and repeated image/pdf assets while the page copy claims all 57 issues are available.",
      "impact": "Users see something that looks like an archive, but it is a fabricated five-row sample instead of the real legacy archive.",
      "recommendation": "Replace the hardcoded sample with real content/data loading and remove any misleading copy until that works."
    },
    {
      "id": "M002",
      "source": "Mock Findings",
      "category": "Mock / dead submit handler",
      "title": "Newsletter page",
      "severity_1_10": 10,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Integrations page [In development (almost done)]; Hidden for newsletter subscribers? Sign-up block [Other backlog]; Newsletter modal [Other backlog]",
      "surface_or_reachability": "Newsletter page",
      "evidence": "src/app/(main)/nyhedsbrev/_components/newsletter-form.tsx:35-39 leaves the submit action as a comment placeholder.",
      "impact": "The primary newsletter signup page looks complete, accepts input, and then does nothing.",
      "recommendation": "Implement the real submit flow or remove the form until it actually performs the promised action."
    },
    {
      "id": "M003",
      "source": "Mock Findings",
      "category": "Mock / stubbed backend",
      "title": "Subscription upgrade",
      "severity_1_10": 10,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Subscription upgrade",
      "evidence": "src/server/modules/payment/services/subscription.service.ts:170-175 returns `{}` from `upgrade()` while src/components/payment/blocks/subscription-card.tsx:144-151 still calls it.",
      "impact": "Users are offered an upgrade flow that is not implemented.",
      "recommendation": "Implement the backend path before exposing the CTA or label the flow as unavailable."
    },
    {
      "id": "A004",
      "source": "Audit Findings",
      "category": "Security",
      "title": "Unauthenticated upload-delete endpoint can delete assets by path or ID",
      "severity_1_10": 9,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Bulk upload images [In development (almost done)]; Captions connected to images [Task from Anders]",
      "surface_or_reachability": "Public API surface",
      "evidence": "src/app/api/upload/delete/route.ts:4-32 accepts DELETE with a `path` query parameter and calls deleteAsset; src/lib/utils/upload-utils.ts:24-33 passes the identifier straight to `nup.deleteAsset`.",
      "impact": "This is an obvious availability and integrity problem. Any caller that can guess or discover an asset path can attempt deletion without authentication.",
      "recommendation": "Require authentication and ownership/permission checks before deletion. Prefer signed, short-lived deletion intents rather than raw public file-path deletion."
    },
    {
      "id": "A005",
      "source": "Audit Findings",
      "category": "Engineering quality",
      "title": "Public `/test-stripe` demo page ships in the deliverable",
      "severity_1_10": 9,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Public route",
      "evidence": "src/app/test-stripe/page.tsx:8-195 renders a public Stripe test dashboard that attempts subscription upgrades, organization creation, and organization listing.",
      "impact": "A public demo/test route on a production magazine codebase is not a harmless leftover. It exposes non-customer flows, confuses acceptance testing, and increases attack surface.",
      "recommendation": "Remove the route from production code or lock it behind an internal-only environment gate."
    },
    {
      "id": "A006",
      "source": "Audit Findings",
      "category": "Engineering quality",
      "title": "Core subscription upgrade path is stubbed while the UI still advertises it",
      "severity_1_10": 9,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Authenticated users",
      "evidence": "src/server/modules/payment/services/subscription.service.ts:170-175 leaves `upgrade()` as TODO and returns `{}`; src/components/payment/blocks/subscription-card.tsx:144-151 still calls it.",
      "impact": "This is not a minor defect. It is an acceptance-critical commerce flow presented as if it works.",
      "recommendation": "Implement upgrade end-to-end or remove/disable the UI until it exists."
    },
    {
      "id": "A013",
      "source": "Audit Findings",
      "category": "Release engineering",
      "title": "App startup hard-requires Stripe and MobilePay env vars even outside payment flows",
      "severity_1_10": 9,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Startup / deploy-time",
      "evidence": "src/config/env.ts:62-84 makes Stripe and MobilePay variables mandatory during env validation; src/server/auth/index.ts:221-252 registers the Better Auth Stripe integration unconditionally and reads plans from the database.",
      "impact": "This blocks minimal bootstraps and makes the app non-portable across environments that only need core web/database/storage services. A release candidate should not refuse to start just because optional payment credentials are absent.",
      "recommendation": "Make payment providers truly optional at startup: gate env validation and provider/plugin registration behind explicit feature flags, and only initialize Stripe/MobilePay when those integrations are enabled."
    },
    {
      "id": "A015",
      "source": "Audit Findings",
      "category": "Release engineering",
      "title": "Fresh databases are incomplete after migrations and require manual Stripe sync plus destructive seed paths",
      "severity_1_10": 9,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Startup / bootstrap",
      "evidence": "package.json:30 wires Stripe sync to a separate `stripe:fetch-plans` command; src/server/commands/payment/stripe-fetch-plans.command.ts:1-15 manually runs `syncAllProducts()` and `syncAllPrices()`; src/server/modules/payment/services/stripe.service.ts:33-50 fetches products/prices from Stripe, while src/server/auth/index.ts:239-252 expects active prices to already exist in the database; src/server/database/seeders/payment-plan.seeder.ts:210-219 skips missing plans, and src/server/database/seeders/payment-price.seeder.ts:102-117 only updates rows that already exist.",
      "impact": "A clean database is not release-ready after migrations alone. Checkout plan resolution depends on Stripe-backed plan/price rows being present, but the repo provides no safe, idempotent production bootstrap for that catalog or for required content/admin scaffolding.",
      "recommendation": "Automate plan and price reconciliation as part of startup or a dedicated idempotent production bootstrap, and keep the mapping driven from live Stripe product metadata instead of contractor-specific preloaded rows. Add a separate non-destructive bootstrap for required pages, blocks, and admin state."
    },
    {
      "id": "A017",
      "source": "Audit Findings",
      "category": "Security / Release engineering",
      "title": "Mailchimp config is split between env and database, and the DB-backed secret path is publicly readable",
      "severity_1_10": 9,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Integrations page [In development (almost done)]; Hidden for newsletter subscribers? Sign-up block [Other backlog]; Newsletter modal [Other backlog]",
      "surface_or_reachability": "Public tRPC + runtime + scheduled jobs",
      "evidence": "src/server/modules/site-config/router/index.ts:7-13 exposes `values` as `publicProcedure`; src/server/modules/site-config/services/site-config.service.ts:21-31 returns the full config map; src/server/modules/site-config/validators/site-config.validator.ts:10-12 includes `MAILCHIMP_API_KEY` and `MAILCHIMP_LIST_ID`; src/components/dashboard/site-config/config-editor.tsx:579-590 writes those values through the admin UI; meanwhile src/server/modules/newsletter/services/newsletter.service.ts:17-21 still defaults the newsletter list ID from env, while src/server/clients/mailchimp/mailchimp.service.ts:16-19 and src/lib/mailchimp/client.ts:6-12 read the API key from site-config; src/server/commands/site-config-update-stats.command.ts:20-35 also reads the list ID from site-config and requires an admin user.",
      "impact": "This is worse than ordinary config drift. The repo creates two competing Mailchimp configuration paths, and the one stored in the database is exposed through a public query if operators use the dashboard for secret storage.",
      "recommendation": "Remove secrets from public site-config entirely, split secret config from public metadata config, and enforce one authoritative Mailchimp configuration path for app and job runtime."
    },
    {
      "id": "A020",
      "source": "Audit Findings",
      "category": "Release engineering / Payments",
      "title": "Stripe catalog sync exists, but plan typing and checkout behavior still depend on mutable plan names",
      "severity_1_10": 9,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Rules for Stripe [Task from Anders]",
      "surface_or_reachability": "Checkout, sync, and subscription update flows",
      "evidence": "src/server/modules/payment/services/stripe.service.ts:54-61 falls back from `metadata.type` to `name.includes('business')`; src/server/auth/index.ts:268-282 derives business and annual behavior from `plan.name`; src/components/subscription/subscription-button.tsx:8-29 upgrades by arbitrary `planName`; src/app/(main)/profile/organization/_components/organization-subscription.tsx:88-97 sends `selectedPlan.plan` into upgrade; meanwhile metadata is already modeled in src/server/modules/payment/tables/plan.table.ts:17-25 and src/server/modules/payment/types/plan-metadata.type.ts:1-6.",
      "impact": "This undermines the whole point of syncing the Stripe catalog. A renamed product or mismatched label can flip business vs personal logic or billing period behavior even when Stripe metadata is correct.",
      "recommendation": "Make metadata authoritative everywhere, pass stable plan identifiers from UI to backend, and remove name-based heuristics from sync and checkout logic."
    },
    {
      "id": "A026",
      "source": "Audit Findings",
      "category": "Release engineering / Operations",
      "title": "Railway deployment definition omits the scheduled job lifecycle entirely",
      "severity_1_10": 9,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Target-platform deployment",
      "evidence": "railway.toml:1-8 defines only build and healthcheck for a single web service; scheduled work exists only in swarm compose, with cron infra at docker-compose.dev.yml:27-38 and jobs at docker-compose.dev.yml:134-195 for MobilePay processing, site-config stats, GA sync, and scheduled publishing.",
      "impact": "A Railway deployment can come up 'healthy' while silently missing the background work that keeps subscriptions, analytics, and scheduled content alive. That is an incomplete production topology, not a minor ops TODO.",
      "recommendation": "Model the target deployment as multiple first-class services or platform schedulers and include those workers in the checked-in Railway deployment path."
    },
    {
      "id": "M004",
      "source": "Mock Findings",
      "category": "Mock / misrepresented behavior",
      "title": "Project alerts",
      "severity_1_10": 9,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "\"Project\" content type [Needed for launch]; Rules for mailing [Task from Anders]; User subscription to the project [Task from Anders]",
      "surface_or_reachability": "Project alerts",
      "evidence": "src/components/shared/post-newsletter-form.tsx:61-69 sends only `{ email }` to the generic newsletter mutation, despite CTA copy promising project-specific alerts.",
      "impact": "The UI claims project update alerts, but the implementation is just a generic newsletter signup.",
      "recommendation": "Either implement the promised behavior or change the UI copy so it stops lying to the user."
    },
    {
      "id": "M010",
      "source": "Mock Findings",
      "category": "Mock / hardcoded fake data",
      "title": "Google Analytics sync",
      "severity_1_10": 9,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Move Google Analytics [Other backlog]",
      "surface_or_reachability": "Google Analytics sync",
      "evidence": "src/server/clients/google-analytics.service.ts:102 injects `/kort/test` with 1000 views, and src/server/commands/update-ga-page-views.command.ts:14-23 persists that fabricated row like real analytics data.",
      "impact": "Analytics can appear populated and healthy even when part of the dataset is synthetic contractor filler.",
      "recommendation": "Replace the fake behavior with a real implementation and re-test the affected surface."
    },
    {
      "id": "A016",
      "source": "Audit Findings",
      "category": "Release engineering",
      "title": "Deployment tooling mixes dev-only mounts, fake production tags, and machine-specific compose files",
      "severity_1_10": 8,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Repo-wide",
      "evidence": "docker-compose.yml:28-31 and 43-55 still use `:dev` image tags and bind mounts; docker-compose.yml:93-99 mounts source and env files directly into the running container; Makefile:189-198 pushes a Swarm-style `docker stack deploy` path; infrastructure/docker/docker-compose.yml:9-10,42-43,69-72 hardcodes another developer's local filesystem.",
      "impact": "This is not a cosmetic cleanup issue. It signals that the deployment story is fragmented and partly non-portable, which increases the chance that the accepted deployment path is undocumented, unreproducible, or simply not the one checked into the repo.",
      "recommendation": "Separate development and production orchestration cleanly, remove bind mounts and `:dev` tags from release definitions, delete or template machine-specific compose files, and document one reproducible deployment path that actually matches the target platform."
    },
    {
      "id": "A018",
      "source": "Audit Findings",
      "category": "Data integrity / Analytics",
      "title": "Google Analytics sync injects hardcoded fake page-view data",
      "severity_1_10": 8,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Move Google Analytics [Other backlog]",
      "surface_or_reachability": "Analytics sync command",
      "evidence": "src/server/clients/google-analytics.service.ts:66-104 appends `result.set('/kort/test', 1000)` after the real GA report loop; src/server/commands/update-ga-page-views.command.ts:11-24 persists every returned path into analytic views.",
      "impact": "This poisons the analytics dataset with fabricated rows and proves the sync path is not trustworthy for acceptance, reporting, or business decisions.",
      "recommendation": "Delete the hardcoded test record, quarantine analytics fixtures to test-only code, and add a regression test that rejects unknown synthetic paths in production syncs."
    },
    {
      "id": "A019",
      "source": "Audit Findings",
      "category": "Release engineering / Analytics",
      "title": "GA credentials are wired as a file-path assumption rather than a deploy-safe secret input",
      "severity_1_10": 8,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Build and runtime configuration",
      "evidence": "src/server/clients/google-analytics.service.ts:15-19 constructs `BetaAnalyticsDataClient()` with default ADC behavior; src/config/env.ts:90-93 exposes only `GOOGLE_APPLICATION_CREDENTIALS`; .env.example:70 points that variable at `/ga-service-account.json`; docker-compose.dev.yml:108-110 passes the path through. Repo search of tracked deploy files found no credential JSON mount or copy beyond that env reference.",
      "impact": "The deployment depends on an undocumented credential file appearing inside the runtime container. That is brittle, hard to reproduce, and not encoded in the checked-in deployment path.",
      "recommendation": "Support env-injected JSON credentials or workload identity, and fail bootstrap with an explicit validation error if the analytics auth mechanism is incomplete."
    },
    {
      "id": "A021",
      "source": "Audit Findings",
      "category": "Release engineering / Runtime",
      "title": "Every runtime container and scheduled job runs migrations on boot",
      "severity_1_10": 8,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Container startup and cron jobs",
      "evidence": "Dockerfile:115-117 and Dockerfile.railway:87-88 set `docker-entrypoint.sh` for all runtime containers; infrastructure/docker/common/docker-entrypoint.sh:66-76 and 104-119 always wait for DB and run `node migrate.js` before the requested command; docker-compose.dev.yml:134-195 defines scheduled job services with the same image and entrypoint pattern.",
      "impact": "App replicas, one-off jobs, and cron tasks all become implicit migration runners. That creates avoidable startup coupling, migration races, and failure modes where an unrelated job cannot run because schema migration behavior changed.",
      "recommendation": "Move schema migration to an explicit one-shot deploy step and keep app and job containers focused on their actual command."
    },
    {
      "id": "A023",
      "source": "Audit Findings",
      "category": "Release engineering",
      "title": "Checked-in bootstrap scripts are local-dev oriented, partially broken, and seed localhost content",
      "severity_1_10": 8,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Repository bootstrap path",
      "evidence": "infrastructure/seed_db.sh:135-145 checks for non-existent `src/lib/database/seed.ts` and tells operators to run missing `./infrastructure/setup_docker.sh`; infrastructure/setup_env.sh:64-132 generates a localhost-only `.env.local`; infrastructure/seed_db.sh:179-195 advertises seeded demo accounts and localhost services; src/server/database/seeders/page.seeder.ts:755-763 hardcodes `http://localhost:3000/faq` into seeded page content.",
      "impact": "The documented bootstrap path is not production-ready. It is misleading, partly broken, and it injects developer URLs and demo assumptions into the dataset that would be unacceptable in a real environment.",
      "recommendation": "Split dev bootstrap from production bootstrap, fix the broken script references, remove localhost URLs from seeded content, and make base content creation idempotent and environment-aware."
    },
    {
      "id": "M005",
      "source": "Mock Findings",
      "category": "Mock / demo/test surface",
      "title": "Public Stripe test page",
      "severity_1_10": 8,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Public Stripe test page",
      "evidence": "src/app/test-stripe/page.tsx:8-195 ships a public demo control panel for test subscription and organization actions.",
      "impact": "A non-customer demo flow is presented on the public app surface.",
      "recommendation": "Replace the fake behavior with a real implementation and re-test the affected surface."
    },
    {
      "id": "A007",
      "source": "Audit Findings",
      "category": "Engineering quality",
      "title": "Default test command is broken by vendored legacy tests",
      "severity_1_10": 7,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Repo-wide",
      "evidence": "package.json:39 defines `test` as `vitest run`; local `pnpm test` fails on `__legacy` suites such as beerslider, googleanalytics, jquery-match-height, and Drupal views tests.",
      "impact": "A deliverable that cannot pass its default test command without manual scoping is not cleanly maintainable or CI-ready.",
      "recommendation": "Exclude `__legacy` from Vitest, or scope tests to the new app explicitly and add that configuration to the repo."
    },
    {
      "id": "A008",
      "source": "Audit Findings",
      "category": "Availability",
      "title": "Public advertiser page crashes at runtime",
      "severity_1_10": 7,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Public route",
      "evidence": "Local GET `http://127.0.0.1:3100/annoncering` returned 500; the running server logged `TypeError: a.map is not a function`. Route source: src/app/(main)/annoncering/page.tsx.",
      "impact": "This is a public-facing commercial page. If the contractor claimed the site was ready, a deterministic runtime 500 on a public route is an acceptance blocker.",
      "recommendation": "Fix the content-shape assumption in the advertising page renderer and add route smoke tests for all public landing pages."
    },
    {
      "id": "A022",
      "source": "Audit Findings",
      "category": "Security / Ops",
      "title": "Migration script logs the full database connection string",
      "severity_1_10": 7,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Migration logs",
      "evidence": "migrate.js:27-34 prints debug state and then logs `Connection string value:` followed by the raw connection string.",
      "impact": "That leaks database credentials into CI, container, or platform logs. It is careless at best and operationally unsafe in any shared logging environment.",
      "recommendation": "Redact secrets in migration logging and keep only non-sensitive connection diagnostics such as host classification or presence checks."
    },
    {
      "id": "A025",
      "source": "Audit Findings",
      "category": "Release engineering / Config",
      "title": "Hardcoded domains and localhost defaults still leak into auth, build config, and seeded content",
      "severity_1_10": 7,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Runtime config + seeded CMS content",
      "evidence": "src/server/auth/index.ts:489-492 falls back to `magasinetkbh.vercel.app` for cross-subdomain cookies; Dockerfile:46-60 bakes localhost and dummy host defaults into build-time auth/app/mobilepay env; src/server/database/seeders/page.seeder.ts:755-763 seeds `http://localhost:3000/faq`; src/app/(main)/payments/personal/page.tsx:28-52 and src/app/(main)/payments/sponsorship/page.tsx:20-44 hardcode live-domain share URLs and legacy asset URLs.",
      "impact": "Wrong host defaults do not stay theoretical. They bleed into cookie scoping, generated links, seeded pages, and public marketing surfaces, which makes deployment behavior environment-dependent and error-prone.",
      "recommendation": "Move every host/domain value behind validated configuration, remove hardcoded domains from seed data and page constants, and fail builds when required public URLs are missing instead of falling back to localhost or contractor domains."
    },
    {
      "id": "M006",
      "source": "Mock Findings",
      "category": "Mock / hardcoded marketing data",
      "title": "Personal payments page",
      "severity_1_10": 7,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Donate [Needed for launch]",
      "surface_or_reachability": "Personal payments page",
      "evidence": "src/app/(main)/payments/personal/page.tsx:136-175 hardcodes `2808` members and `MobilePay 711911`; lines 28-52 use legacy asset URLs.",
      "impact": "The page mixes real dynamic plan data with fake/static proof points that can mislead acceptance review and end users.",
      "recommendation": "Replace the fake behavior with a real implementation and re-test the affected surface."
    },
    {
      "id": "A024",
      "source": "Audit Findings",
      "category": "Engineering quality / Admin tooling",
      "title": "The dashboard 'Google' integration UI does not control the actual analytics integration",
      "severity_1_10": 6,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Added googke ads api_id to config BE [Needed for launch]; Google Ads? (FE) [Needed for launch]; Integrations page [In development (almost done)]",
      "surface_or_reachability": "Admin dashboard + runtime config",
      "evidence": "src/server/modules/site-config/enums/site-config-key.enum.ts:7-9 only defines `GOOGLE_ADS_ID` for Google-related site-config; src/components/dashboard/site-config/config-editor.tsx:571-577 exposes only 'Google ADS Id' in the integrations tab; actual page tagging uses env-backed config in src/app/layout.tsx:31 and src/config/env.ts:240-244, while server-side GA reporting uses env-backed config in src/server/clients/google-analytics.service.ts:17-18.",
      "impact": "Operators are shown a Google integration control panel that does not actually govern the live analytics implementation. That is a fake control surface and a reliable way to misconfigure production.",
      "recommendation": "Either wire the admin UI to the real integration state or remove it. Keep Ads, GA tag ID, GA property ID, and service-account auth as explicit, separately documented settings."
    },
    {
      "id": "M007",
      "source": "Mock Findings",
      "category": "Mock / manual fallback posing as productized flow",
      "title": "Sponsorship page",
      "severity_1_10": 6,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Sponsorship page",
      "evidence": "src/app/(main)/payments/sponsorship/page.tsx:92-97 converts through `mailto:` and lines 20-44 and 111-117 pull legacy-hosted assets.",
      "impact": "The surface looks migrated, but conversion is still manual and piggybacks on legacy assets.",
      "recommendation": "Replace the fake behavior with a real implementation and re-test the affected surface."
    },
    {
      "id": "M008",
      "source": "Mock Findings",
      "category": "Mock / reduced implementation sold as full feature",
      "title": "Guest links",
      "severity_1_10": 6,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Set paywall access? [In development (almost done)]",
      "surface_or_reachability": "Guest links",
      "evidence": "src/components/dashboard/post/post-guest-link-dialog.tsx:17-66 only supports an optional expiration date; it does not implement the requested one-time mode and builds the link with raw `token` querystring.",
      "impact": "Editors are given a 'guest link' tool that looks finished, but it omits key promised behavior.",
      "recommendation": "Replace the fake behavior with a real implementation and re-test the affected surface."
    },
    {
      "id": "A009",
      "source": "Audit Findings",
      "category": "Performance",
      "title": "Homepage and article routes do heavy server work without evidence of caching discipline",
      "severity_1_10": 5,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Public routes",
      "evidence": "src/app/page.tsx:38-118 fires eleven server fetches for the homepage; article pages such as src/app/(main)/inhold/[slug]/page.tsx:47-66 fetch content and trigger analytics on render.",
      "impact": "The code may work at low volume, but it leaves too much expensive server work on hot public routes without visible acceptance evidence for caching or performance budgets.",
      "recommendation": "Add explicit caching strategy, route-level performance budgets, and smoke benchmarks for the homepage and article detail routes."
    },
    {
      "id": "A010",
      "source": "Audit Findings",
      "category": "Security / Quality",
      "title": "Auth configuration still contains demo/test-only values",
      "severity_1_10": 4,
      "dnc_signal": "Mentioned/related in DnC",
      "dnc_reference": "Integrations page [In development (almost done)]",
      "surface_or_reachability": "Repo-wide",
      "evidence": "src/server/auth/index.ts:101 trusts provider `demo-app`; src/server/auth/index.ts:473-480 injects `dd: \"test\"` into the session payload.",
      "impact": "These are not catastrophic on their own, but they are classic signs of unfinished or non-production auth hardening.",
      "recommendation": "Remove demo-only trusted providers and test payload fields before acceptance."
    },
    {
      "id": "A011",
      "source": "Audit Findings",
      "category": "Engineering quality",
      "title": "Next.js middleware convention is deprecated in the current framework version",
      "severity_1_10": 3,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Build-time",
      "evidence": "Local `pnpm build` emitted `The \"middleware\" file convention is deprecated. Please use \"proxy\" instead.`; repo uses src/middleware.ts:1-52. Official Next.js 16.1.5 docs confirm `middleware` is deprecated and renamed to `proxy`.",
      "impact": "This is not a business-critical defect, but it is a clear sign the contractor did not finish framework hygiene on a modern stack they chose themselves.",
      "recommendation": "Run the official Next.js middleware-to-proxy migration and update the file/export convention."
    },
    {
      "id": "A012",
      "source": "Audit Findings",
      "category": "Security / Ops",
      "title": "Public health endpoint reveals uptime, environment, version, and database state",
      "severity_1_10": 3,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Public route",
      "evidence": "src/app/api/health/route.ts:4-55 returns environment, uptime, version, and database connectivity status to any caller.",
      "impact": "Health checks are useful, but this version discloses more operational detail than necessary for a public website.",
      "recommendation": "Restrict detailed health data to internal callers or return a minimal boolean/liveness response publicly."
    },
    {
      "id": "M009",
      "source": "Mock Findings",
      "category": "Mock / dead hardcoded fallback",
      "title": "Organization pricing component",
      "severity_1_10": 3,
      "dnc_signal": "New discovered issue",
      "dnc_reference": "",
      "surface_or_reachability": "Organization pricing component",
      "evidence": "src/app/(main)/profile/organization/_components/organization-content.tsx:19-110 contains a hardcoded business plan table and `currentPlan` fixed to `undefined`, but the active route uses a different component.",
      "impact": "Not currently user-visible on the active route, but it is still unfinished fallback code that imitates real pricing logic.",
      "recommendation": "Replace the fake behavior with a real implementation and re-test the affected surface."
    }
  ],
  "summary": {
    "total_features": 66,
    "full_count": 28,
    "partial_count": 26,
    "skipped_count": 12,
    "dnc_mentioned_count": 42,
    "dnc_not_mentioned_count": 24,
    "dnc_working_count": 22,
    "dnc_blocked_count": 19,
    "dnc_wont_do_count": 1,
    "audit_findings_count": 26,
    "mock_findings_count": 10,
    "findings_mentioned_in_dnc": 13,
    "findings_new_issue": 23
  }
}