SKILL.md
Contract-First API Workflow
Run this skill after modifying backend REST resources or DTOs to sync the OpenAPI contract and regenerate the frontend/mobile clients.
Step 0 — Bump the API contract version (always, before generating)
pedalons.api.version in backend/src/main/resources/application.properties is the single source of truth for the contract version. It feeds both info.version in contracts/openapi.yaml and GET /api/version (which also reports the git commit the server was built from), so deployments can be identified. Bump it whenever the contract changes — semver on the contract itself:
- MAJOR — breaking change: endpoint or field removed/renamed, type changed, optional field became required
- MINOR — backwards-compatible addition: new endpoint, new optional field
- PATCH — descriptions/docs only
If the generated contracts/openapi.yaml diff turns out to be empty, revert the bump.
One-shot (preferred)
The repo root has regenerate.sh, which runs the whole chain end-to-end and fails fast (set -e):
bash regenerate.sh
It performs, in order:
cd backend && mvn clean package -DskipTests— generatescontracts/openapi.{yaml,json}cd frontend && pnpm check— see belowcd mobile && bash check.sh— see below
Prefer this over running the steps by hand so nothing drifts out of sync.
Steps (what the scripts do)
1. Generate OpenAPI Contract
cd backend && mvn clean package -DskipTests
Generates contracts/openapi.yaml and contracts/openapi.json.
2. Regenerate Frontend Client — pnpm check
cd frontend && pnpm check
pnpm check expands to: pnpm install && pnpm generate-api && pnpm generate-routes && pnpm format && pnpm typecheck && pnpm lint && pnpm build.
generate-apiruns Orval →src/api/dto/,src/api/endpoints/,src/api/zod/generate-routesregenerates the UI routes contract (paths.generated.*, AASA, deeplinks) fromcontracts/routes.yaml— don't skip this; it's part of the contract surfacetypecheck(tsgo -b) is the real type gate — notbuild
3. Regenerate Mobile Client — check.sh
cd mobile && bash check.sh
check.sh runs: flutter pub get && dart run openapiretrofitgenerator && dart run build_runner build && flutter analyze.
- Generates
lib/api/generated/clients/(Retrofit) andlib/api/generated/models/(Freezed) flutter analyzeverifies no Dart errors
After Running
- Report any errors from the generation or verification steps.
- If there are TypeScript or Dart errors, help fix them.
Common Issues
- Empty schemas in OpenAPI: Missing
@Schema(implementation = ...)in@APIResponseannotations - Orval errors: Usually caused by an invalid OpenAPI spec — check backend annotations
- Mobile buildrunner conflicts:
buildrunner builddeletes conflicting outputs by default (the old--delete-conflicting-outputsflag was removed in build_runner 2.5.0) @Tagname collides in the mobile client: the tag becomes a getter on the generatedPedalonsApiClient, which already carriesstatic String get version. A tag namedVersiontherefore produces a Dart compile error, andflutter analyzewon't catch it (analysis_options.yamlexcludeslib/api/generated/**) — rundart analyze lib/api/generated/after renaming a tag.- Renaming a
@Tagleaves stale generated files: the mobile generator writes the new*_client.dartbut doesn't delete the old one; remove it by hand.