# store-directory Specification ## Purpose The buyer-facing view of a shop: its public profile — identity, contact and service copy — alongside the products it sells, so the store directory, a store's home page and the store card on a product page all read real shops. ## Requirements ### Requirement: Public shop directory `GET /api/shops` SHALL list the active shops without authentication, and `GET /api/shops/{slug}` SHALL return one shop by slug, answering 404 for an unknown slug or a suspended shop. Each entry SHALL carry the shop's id, slug, bilingual name and its profile: logo and banner URLs, company, region, bilingual address, bilingual notice and after-sale copy, and four score values. A shop with no profile row SHALL still be returned, with the profile fields absent rather than invented. #### Scenario: directory lists active shops only - **WHEN** a suspended shop exists alongside active ones - **THEN** the directory lists only the active shops #### Scenario: store home by slug - **WHEN** a shopper opens a shop's slug - **THEN** the profile and the shop's products are available, with the products filtered by that shop through the catalog API #### Scenario: unknown slug is a 404 - **WHEN** a shopper opens a slug that does not exist - **THEN** the API answers 404 rather than an empty profile ### Requirement: Shop profile management A platform admin SHALL set a shop's profile with `PUT /api/admin/shops/{id}/profile`, which upserts the profile row and returns the composed shop. Bilingual fields SHALL carry non-empty `en` and `zh` text, and the write SHALL require the `platform_admin` role. #### Scenario: profile upsert round-trips - **WHEN** an admin sets a profile and then reads the shop publicly - **THEN** the public read returns those values #### Scenario: incomplete bilingual text is refused - **WHEN** an admin submits a notice with only `en` text - **THEN** the request is refused and the stored profile is unchanged #### Scenario: only platform admins may write - **WHEN** a shop owner or customer submits a profile - **THEN** the API refuses the write