- ID
- 3392fa99-0fc4-440a-a157-60a6e00c6a3c
Hungryroot 2026 Q2 Goals Draft
# Q2 2026 — API/Backend goals
Status: draft. Owner: Colin Powell. Quarter: Q2 2026 (Apr–Jun). Authored 2026-05-18.
## Summary
Support Brand Pod Q2 execution by hardening the API platform that brand and growth surfaces depend on — reducing integration friction, accelerating cross-team release velocity, and making Brand a first-class entity in the backend. This includes:
- **Consolidating the API surface** by completing the V1 → V2 transition so client teams build against one consistent, documented contract.
- **Unblocking mobile delivery** through standing visibility into iOS/Android endpoint dependencies, named owners on both sides, and a minimum-supported-version policy that retires long-tail clients.
- **Preventing cross-team integration defects** by introducing automated contract testing (Schemathesis for schema accuracy, Pact for consumer-driven contracts and a `can-i-deploy` release gate).
- **Elevating Brand to a first-class backend concept** with a canonical `Brand` model, image and metadata, and a migration path off the denormalized `Product.brand_name` string.
Success means delivering an API platform where brand and growth surfaces ship faster, with fewer mobile integration regressions, against a documented contract — and where Brand-driven product experiences (logos, descriptions, brand-filtered discovery) are supported natively rather than bolted onto a free-text field.
### Workstreams
1. Finish V1 → V2 traffic transition.
2. Follow up with iOS/Android on remaining endpoints.
3. Stand up automated API contract testing (Schemathesis + Pact, two-phase).
4. Make Brand a first-class concept in the backend.
Workstreams 1, 2, and 3 are coupled: contract tests reduce migration risk; mobile sync unblocks deprecations. Workstream 4 is independent but benefits from the contract harness for new endpoints.
---
## 1. Finish V1 → V2 traffic transition
**Why now:** v2 noslash variants just removed (BE-7208 #14018). Migration entering tail end — long-tail clients are the remaining risk.
**Workstreams**
- **Datadog traffic audit** — query `/api/v1/*` hits over rolling 7d. Bucket by route + client (`User-Agent`, app version). Identify which v1 endpoints still see non-zero traffic.
- **Per-route migration tickets** — one BE ticket per remaining v1 route with traffic. Each: confirm v2 equivalent exists, file client migration ask, set deprecation date.
- **Deprecation header rollout** — return `Deprecation` + `Sunset` headers on remaining v1 routes so clients surface in logs/Sentry.
- **Kill-switch dry-run** — for routes <X req/day, gate behind dynamic-config flag; flip in staging, confirm no breakage, schedule prod flip.
- **Close out BE-7208** — already in *Testing in Progress*. Finish remaining trailing-slash audit work.
**Success criteria**
- v1 traffic <1% of total API requests (or named exempt list).
- Every remaining v1 route has either: (a) sunset date in client backlog, or (b) documented exemption.
- Deprecation headers live on all v1 routes.
**Risks**
- Long-tail client versions never auto-update — need product alignment on minimum-supported-version bump.
---
## 2. iOS/Android endpoint followups
**Why now:** Mobile owns the slowest-moving client. Need standing visibility, not ad-hoc asks.
**Workstreams**
- **Mobile endpoint matrix** — Confluence/Notion page listing every endpoint mobile calls, current version (v1/v2/v3), latest app version using it. Source: Datadog `app.version` tag breakdown.
- **Sync cadence** — biweekly 30-min with iOS + Android leads. Agenda: what's left, what's blocking, what they need from BE.
- **Per-platform migration tickets** — file under shared epic. Mobile owns app-side; BE owns endpoint readiness + parity testing.
- **Minimum-version policy** — propose with mobile + product: after N months, force-upgrade clients on retired v1 routes.
**Success criteria**
- Matrix exists + refreshed monthly.
- Every mobile-called v1 route has named owner on both sides + target date.
- Force-upgrade policy documented + first enforcement date set.
**Risks**
- App-store review cycles add weeks. Bake into target dates.
- iOS/Android may not have eng capacity — need EM-level commitment.
---
## 3. Automated API contract testing — Schemathesis + Pact (two-phase)
**Why now:** Proposal already drafted ([Backend Project Proposal: Contract Testing with Schemathesis and Pact](https://hungryroot.atlassian.net/wiki/spaces/BA/pages/1535868929/)). Phase 1 timeline starts 5/4 — already in flight as of 5/18. Phase 2 spills into Q3 (ends 7/26). Treat Phase 1 closeout as Q2 commit; Phase 2 = Q2 kickoff + Q3 finish.
### Phase 1 — Schemathesis (Q2 commit, 5/4 – 5/31)
Harden the OpenAPI schema as the single source of truth for client integrations by validating it against actual backend behavior in CI. This includes:
- **Closing the gap between documented and implemented contracts** by running property-based tests over the `drf-spectacular` schema and surfacing every request/response mismatch.
- **Raising the quality of generated schema annotations** so downstream consumers (mobile codegen, Phase 2 Pact contracts, future SDKs) inherit accurate types instead of best-guess shapes.
- **Establishing a required CI gate** for schema drift, so annotation gaps and breaking changes are caught at PR time rather than at integration.
- **Documenting the harness** so any backend engineer can run, extend, and triage contract failures without specialist knowledge.
Success means the top 20 endpoints by mobile traffic are covered by property-based contract validation, schema/implementation mismatches stop escaping to staging, and Phase 2 (Pact) starts from a trustworthy schema foundation rather than papering over drift.
**Objective:** Validate OpenAPI schema against actual request/response behavior. Catch drift in CI.
**Workstreams**
- Add `schemathesis` to `requirements-test.txt`.
- Scaffold `app/tests/rest/contract/` — property-based tests load `drf-spectacular` schema, run via Django test client (no live server needed).
- Factory Boy auth fixtures for protected endpoints.
- Triage + fix `drf-spectacular` annotation gaps revealed by Schemathesis.
- New `contract-tests` job in `.github/workflows/django-tests.yml` — required check.
- Runbook: how to run locally, how to triage failures.
**Coverage target**
- Top 20 endpoints by mobile traffic / error budget. Auth (login/refresh/logout), user profile, highest-traffic domain reads.
**Success criteria (per proposal)**
- ≥90% of top 20 endpoints validated by Schemathesis.
- Zero schema/implementation mismatches escape to staging post-Phase 1.
- CI stage green + required.
**Risks**
- Schema annotation gaps wider than estimated → extends Phase 1.
- *Mitigation:* daily triage, parallelize fixes, prioritize by traffic.
**Owner:** [unassigned]
### Phase 2 — Pact (Q2 kickoff 6/1, finish Q3 by 7/26)
**Objective:** Consumer-driven contracts with iOS + Android. `can-i-deploy` gate blocks incompatible releases.
**Workstreams**
- Cross-team kickoff (target 6/3): ownership, versioning, contract-freeze rules.
- Stand up PactFlow free tier broker.
- iOS + Android each author top 10 consumer pacts, publish on release branches.
- BE adds `pact-python`, provider-verification job in CI.
- Broker webhook → triggers provider verification on new consumer pact publication.
- Release pipeline step calls `can-i-deploy`; blocks incompatible deploys.
- Runbooks: pact authorship, verification failures, versioning.
**Success criteria (per proposal)**
- PactFlow live, automated verification green.
- 100% releases guarded by `can-i-deploy`.
- ≥50% reduction in mobile-backend integration defects within 2 release cycles.
**Risks**
- Cross-team coordination overhead — needs Android + iOS lead commitment.
- *Mitigation:* kickoff training, examples repo, clear SLAs.
- Test-data nondeterminism breaks provider verification.
- *Mitigation:* seeded factories, stable provider states.
**Owners:** Backend lead (verification + gate), Android lead (consumer pacts), iOS lead (consumer pacts).
### Coupling to other Q2 goals
- **Couples to goal 2:** Phase 2 kickoff = the forcing function for the biweekly iOS/Android cadence. Bring contract testing onto that agenda.
- **Couples to goal 1:** Schemathesis only runs against documented endpoints. v1 routes outside `drf-spectacular` won't get coverage — another reason to retire them.
- **Couples to goal 4:** new Brand endpoints land *after* Phase 1 — they should be born with accurate schema annotations + included in contract coverage.
### Immediate next actions (this week)
- [ ] Assign Phase 1 owner.
- [ ] Add `schemathesis` to `requirements-test.txt`, scaffold `app/tests/rest/contract/`.
- [ ] Open PR with `contract-tests` CI job (non-blocking initially).
- [ ] Schedule 6/3 cross-team Pact kickoff.
---
## 4. Brand as first-party backend concept
Elevate Brand from a denormalized text field on Product to a canonical entity that the rest of the platform — discovery, search, merchandising, and client surfaces — can build against. This includes:
- **Establishing canonical brand identity** with a stable `Brand` model carrying slug, display name, marketing copy, and visual assets, replacing inconsistent `Product.brand_name` strings.
- **Enabling brand-driven product experiences** through a Product ↔ Brand relationship that supports brand-filtered discovery, brand pages, and brand-aware search ranking.
- **Preserving search and discovery quality** by indexing canonical brand data in Algolia/OpenSearch with read-fallback to the legacy field during transition.
- **Giving ops a real management surface** for brand metadata (logos, descriptions, activation state) instead of free-text edits per product.
Success means brand and growth teams can launch brand-led merchandising and discovery experiences against a real model — with consistent spelling, shared assets, and clean cardinality — without requiring a one-off integration per surface.
**Why now:** Plan doc already drafted ([`docs/brand/first-class-brand-model-plan.md`](./brand/first-class-brand-model-plan.md)). Q2 = land Phase 1, scope Phase 2.
### Phase 1 — Model + admin (Q2 commit)
- `Brand` model: `name`, `slug`, `description`, `image`, `is_active`, `sort_order`.
- `ProductBrand` through model with `is_primary`.
- Migration + backfill management command from distinct `Product.brand_name` values.
- `BrandAdmin` + `ProductAdmin` autocomplete.
- Read-only API endpoints (list/detail by id + slug).
- Algolia/OpenSearch: index `brand.name` alongside existing `brand_name`.
### Phase 2 — Product integration (Q2 stretch / Q3)
- Product serializers embed `brands` minimal payload.
- `brand` / `brands` filter on `ProductFilter`.
- Read-path switch: prefer `Brand.name`, fall back to `brand_name`.
### Phase 3 — Deprecation (Q3+)
- Stop writes to `brand_name`. Field removal after adoption metrics.
### Open questions (resolve early Q2)
- Product confirms cardinality: M2M vs FK? Plan assumes M2M; FK is simpler.
- Image storage: reuse `Product` image conventions or new abstraction?
- Client surface for v3 product responses — coordinate with goal 1.
### Success criteria
- Phase 1 shipped to prod, backfill run, admin in use by ops.
- Phase 2 scoped + first endpoint integration merged.
- No client deprecation of `brand_name` yet (Q3).
### Risks
- Backfill normalization (slug collisions, misspellings) — needs ops review queue.
- Algolia reindex cost / timing — coordinate with search team.
---
## Cross-cutting
- **Tracking:** epic per goal, weekly status in pod sync.
- **Capacity check:** 4 goals in ~6 remaining weeks is ambitious. Recommend Brand Phase 1 + contract Phase 1 as must-land; V1→V2 + mobile sync as continuous progress, not 100% complete.