Feature: Domain not-found errors instead of raw GORM errors As the maintainer of RenewCMS I want a missing article or user reported as a domain not-found error So that the API answers 404 for it instead of leaking a raw GORM error as a 500, and so that a caller can rely on errors.Is(err, article.ErrArticleNotFound) or errors.Is(err, user.ErrUserNotFound) Background: Given internal/domain/article defines the sentinel article.ErrArticleNotFound And internal/domain/user defines the sentinel user.ErrUserNotFound And ArticleRepository.Get and ArticleRepository.GetByName return article.ErrArticleNotFound, not gorm.ErrRecordNotFound, when no row matches And UserRepository.Get, UserRepository.GetByUsername and UserRepository.GetByEmail return user.ErrUserNotFound, not gorm.ErrRecordNotFound, when no row matches And GET /v1/article/{id} sits behind the jwtauth Verifier and Authenticator group, and requires a valid jwt cookie Scenario Outline: The article repository reports a missing article as a domain error Given a repository backed by an in-memory SQLite database containing an article titled "Backyard Renovation Update" with id 1 When is called with Then the result is the error article.ErrArticleNotFound And errors.Is(err, gorm.ErrRecordNotFound) is false Examples: | method | input | | Get | id 9 | | GetByName | "Unknown Title" | Scenario Outline: The user repository reports a missing user as a domain error Given a repository backed by an in-memory SQLite database containing a user with id 1, username "alice" and email "alice@example.com" When is called with Then the result is the error user.ErrUserNotFound And errors.Is(err, gorm.ErrRecordNotFound) is false Examples: | method | input | | Get | id 9 | | GetByUsername | "bob" | | GetByEmail | "bob@example.com" | Scenario: Fetching a nonexistent article answers 404, not 500 Given a valid jwt cookie for a user with id 1 And the article repository has no article with id 9999 When the client sends GET /v1/article/9999 with that cookie Then the response status is 404 And the response body is the text "Article not found" Scenario: Fetching an offline article still answers 404 with the same message Given a valid jwt cookie for a user with id 1 And the article repository contains an article with id 2, is_online false When the client sends GET /v1/article/2 with that cookie Then the response status is 404 And the response body is the text "Article not found" Scenario: Fetching an online article still answers 200 Given a valid jwt cookie for a user with id 1 And the article repository contains an article with id 1, is_online true When the client sends GET /v1/article/1 with that cookie Then the response status is 200 And the response body is the article's JSON representation Scenario: The article route still requires authentication before existence is even checked Given no jwt cookie is sent And the article repository has no article with id 9999 When the client sends GET /v1/article/9999 without a cookie Then the response status is 401 Scenario Outline: Login never reveals whether the username exists Given a user repository containing a user "alice" with password "hunter2example" When the client sends POST /v1/auth/login with username "" and password "" Then the response status is 403 And the response body is the text apperr.LogsErrorMessage And no jwt cookie is set Examples: | username | password | case | | alice | wrongpassword12 | existing user, bad pass | | bob | hunter2example | unknown username |