* feat: make forcePathStyle configurable per storage Previously hardcoded to true, which breaks S3-compatible backends that require virtual-hosted-style addressing (e.g. Alibaba Cloud OSS). Now configurable via admin storage settings with a toggle switch, defaulting to true for backwards compatibility. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test: cover storage force path style --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: saltbo <saltbo@foxmail.com>
Product specs
Behaviour-first product specs in Gherkin .feature files. This directory is the
source of truth for what ZPan does, independent of implementation. There is
no Cucumber runner — the .feature files are documentation, and tests trace
back to scenarios by id.
Convention
-
One
.featurefile per capability (storages.feature,site-invitations.feature, …). -
Each scenario carries two tags: the id
@<capability>/<slug>and the layer that proves it (@domain/@usecase/@web/@api/@e2e):@storages/create-records-activity @api Scenario: Creating a storage records an audit activity Given an authenticated admin When they create a storage Then a storage_create activity is recorded -
The id never changes once written (rename = new id).
-
Verify each scenario at the cheapest layer that can prove it. In this repo most land at
@api(the workerd + real-D1*.integration.test.ts/*.cf-test.tsflows throughapp.fetch) or@web(jsdom + MSW). Reserve@e2efor the Playwright cross-stack journeys. Pure rules sit at@domain/@usecase.
Traceability
Each scenario's home test carries [spec: <id>] in its name:
it('records a storage_create activity [spec: storages/create-records-activity]', …)
pnpm lint:spec (wired into CI) enforces the link both ways: every scenario id must
have a referencing test, and every [spec: id] breadcrumb must match a real scenario.
Status
Specs are authored capability-by-capability alongside the clean-architecture
migration (see docs/clean-arch-migration.md). Migrated capabilities are specced
and traced here; the rest land as their slices migrate.
Escalation
If a non-technical audience ever needs to run the Gherkin, wire playwright-bdd
(compiles .feature → Playwright). These are real .feature files, so that step is
drop-in — no rewrite.