MotoPartPicker
Free motorcycle aftermarket parts compatibility tool with community-verified fitment data and multi-retailer price comparison. This document defines all requirements from MVP through V2.0.
Document Overview
1.1 Purpose
This Business Requirements Document (BRD) defines the functional, non-functional, data, and integration requirements for MotoPartPicker — a free, community-powered motorcycle aftermarket parts compatibility and price comparison platform. It is intended as the authoritative reference for product, engineering, design, and business development teams through the V2.0 release cycle.
The document captures requirements derived from an expert panel including a power-user rider, a supply-side e-commerce manager, a constrained first-time rider, and a product designer with PCPartPicker experience. All requirements have measurable acceptance criteria to enable unambiguous engineering decisions.
1.2 Scope
This BRD covers:
- MVP (P0): Core bike selection, parts compatibility lookup, community verification, and multi-retailer price comparison — targeting the top 20 most-sold motorcycles (2018–present) with 40+ verified parts each. No consumer payments; affiliate links only.
- V1.1 (P1): Build system, affiliate tracking, popular builds, retailer API ingestion, and user reputation. 3–6 months post-launch.
- V1.2 (P2): Modification stacking and conflict detection, retailer fitment intelligence feed, install guides, and cost calculator. 6–12 months post-launch.
- V2.0 (P3): Manufacturer verification portal, VIN decode, shop integration, and AR fit check. 12–18 months post-launch.
Out of scope: OEM parts catalogs, dealer inventory management, vehicle insurance or financing, direct B2C e-commerce (MotoPartPicker does not hold inventory or process consumer payments).
1.3 Stakeholders
| Stakeholder | Role | Interest | Engagement |
|---|---|---|---|
| Product Owner | Founder / Solo Developer | Product strategy, revenue model | Decision authority |
| Rider Community | Primary end users (Jake, Maria archetypes) | Accurate fitment data, fast research | Beta testers, data contributors |
| Aftermarket Retailers | Revenue partners (RevZilla, Rocky Mountain, Partzilla) | Qualified referral traffic, reduced returns | Affiliate + data subscription partners |
| Aftermarket Manufacturers | Data contributors (Yoshimura, Woodcraft, Rizoma) | Accurate fitment representation, brand visibility | V2.0 partner program |
| Engineering Team | Implementation | Unambiguous, testable requirements | Primary consumers of this document |
| Legal / Compliance | Advisory | CCPA, FTC affiliate disclosure, WCAG 2.1 AA | Review before launch |
Business Objectives
The following five objectives define the measurable business outcomes MotoPartPicker must achieve. They are listed in priority order and apply to the first 12 months post-launch unless otherwise noted.
User Personas
Four primary personas were developed through an expert panel process. These personas represent the demand side (riders) and supply side (retailers) of the platform. All product decisions should be evaluated against these personas.
Functional Requirements
Requirements are organized by feature area and assigned a unique identifier (FR-001 through FR-074). Each requirement includes a priority, description, and acceptance criteria. Priority follows the P0–P3 scale where P0 = MVP, P1 = V1.1, P2 = V1.2, P3 = V2.0.
4.1 Bike Selection & Management
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-001 | P0 | Year/Make/Model selector (3-step cascade) | Cascading dropdowns: Year (2015–present) → Make → Model. Each step filters the subsequent step. Selector completes in 3 interactions or fewer. Keyboard navigable. Mobile-optimized touch targets (min 44px). |
| FR-002 | P0 | Variant/Trim disambiguation | When a model has multiple variants (e.g., MT-07 vs MT-07 SP), system prompts for variant selection after model step. Variant is optional — default to "any/all" if user skips. Display warning badge when variant-specific data differs from generic model data. |
| FR-003 | P0 | Session bike persistence | Selected bike persists across all pages during a single session without requiring login. Bike shown in a sticky "Your Bike" header bar on all compatibility pages. "Change bike" CTA clears session state. |
| FR-004 | P0 | Unsupported bike graceful fallback | If selected bike has zero compatibility records, display an informative empty state with: (1) count of community members riding the same model, (2) top 3 most-requested parts for that model, (3) CTA to "Be the first to contribute a verified fit." Never show a blank error state. |
| FR-005 | P1 | Saved garage (multiple bikes) | Authenticated users can save up to 5 bikes to their garage. Garage bikes are selectable from a persistent dropdown. Each garage bike maintains its own saved build history. Anonymous users see a prompt to sign up to save bikes after 2nd visit. |
| FR-006 | P3 | VIN decode to exact variant | User enters 17-character VIN. System decodes Year/Make/Model/Variant using NHTSA API or licensed decoder. Decoded bike is pre-filled in the selector. System flags when VIN resolves to a mid-year revision with different fitment data than the standard model-year entry. |
4.2 Parts Discovery & Compatibility
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-007 | P0 | Outcome-based entry for beginners | Homepage and bike-selected landing page offer outcome-based cards (e.g., "Protect my bike from drops," "Make it louder," "Get more comfortable"). Clicking an outcome maps to one or more mod categories. Outcome cards are shown by default; expert category browsing is available via toggle. Outcomes are informed by most-searched terms for that bike model. |
| FR-008 | P0 | Confidence badge system (3 states) | Every compatibility record displays exactly one of three badges: (1) Verified Fit — confirmed by manufacturer spec, retailer API, or 3+ community verifications with photos; (2) Community Reported — 1–2 community reports, no photo evidence; (3) No Data — part listed but no fitment data for this bike. Badges are color-coded: green, amber, gray respectively. Badge label is always visible (not icon-only) for accessibility. |
| FR-009 | P0 | Parts search with fitment filter | Full-text search across part name, brand, and category, pre-filtered to selected bike. Search results render within 500ms. Results show: part name, brand, confidence badge, lowest price, verification count. Results are sorted by confidence descending by default. Search preserves bike context. |
| FR-010 | P0 | Part detail page | Each part has a dedicated page showing: full name, brand, category, all bikes it fits (with confidence badges), all retailer prices (sorted cheapest first), verification history with usernames and dates, install notes from community. Page is SSR-rendered for SEO indexing. Canonical URL format: /parts/[brand]-[part-slug]. |
| FR-011 | P0 | Category browsing | Parts organized into 8 top-level categories: Exhaust, Suspension, Ergonomics, Protection, Lighting, Electronics, Cosmetic, Other. Each category shows total part count and verified-fit count for selected bike. Category pages are indexable by search engines. |
| FR-012 | P0 | Mid-year revision warnings | When a part's compatibility differs between production variants of the same model-year (e.g., MT-07 2019 early vs. late production), display a warning banner on the part detail page specifying the affected variant range and the nature of the incompatibility. Warning is visually distinct from confidence badges. |
| FR-013 | P1 | Popular builds for your bike | Bike-specific landing page shows "Popular builds for [Year Make Model]" section listing the 5 most-saved public builds. Each build card shows: owner username, number of parts, total estimated cost, and top 3 part names. Clicking navigates to the full build page. |
| FR-014 | P2 | Modification stacking conflict detection | When a user adds a part to their active build, system checks for known conflicts with already-added parts. Conflict is displayed as an inline warning: "[Part A] is reported as incompatible with [Part B] by N community members." Conflicts are non-blocking — user can proceed but must acknowledge the warning. Conflict data is drawn from community-reported incompatibility records. |
| FR-015 | P2 | Install difficulty rating | Community members can rate install difficulty on a 3-point scale: Beginner / Intermediate / Expert. Rating is displayed on part detail and in search results. Displayed as text label plus icon. Requires minimum 3 ratings before displaying. Rating updates in real time after new submissions. |
4.3 Community Verification System
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-016 | P0 | Confirm/deny fit submission | Authenticated users can submit a "confirms fit" or "does not fit" vote for any part on their registered bike. Submission requires: bike year/make/model/variant selection, fit outcome, optional install notes (max 500 chars), optional photo upload (max 3, 5MB each, JPEG/PNG/WEBP). Submissions are attributed to the user's account. Anonymous voting is not permitted. |
| FR-017 | P0 | Confidence score calculation | System computes a confidence score (0–100) for each Part+Bike compatibility record based on: number of confirms, number of denials, recency of submissions, and whether submissions include photo evidence. Score determines badge assignment: 80–100 = Verified, 40–79 = Community Reported, 0–39 = No Data (for records with submissions). Formula is documented in the data model. |
| FR-018 | P0 | Photo upload with install evidence | Photo uploads are stored in cloud object storage (S3-compatible). Photos are resized to max 1200px on the longest edge on ingest. Photos are served via CDN. Each photo is attributed to the submitting user. Moderators can remove photos that violate community guidelines. Photos that include install evidence (part physically on bike) count for 1.5x in confidence scoring. |
| FR-019 | P0 | Verification history timeline | Part detail page shows a chronological list of all verifications for the selected bike. Each entry shows: username, date, outcome (fit/no fit), install notes, and photo thumbnails. Timeline is sorted newest first. Maximum 20 entries shown with "Show more" pagination. |
| FR-020 | P0 | Moderation queue for flagged content | Any user can flag a verification as spam, inaccurate, or inappropriate. Flagged content enters a moderation queue. Admin reviews and approves/removes within 48 hours. Removed verifications are excluded from confidence score recalculation. Users with 3+ removed verifications are automatically placed on a submission probation period. |
| FR-021 | P1 | Contributor reputation system | Users earn reputation points: +5 per accepted verification, +10 per photo-verified install, +20 for "top answer" votes from other users, -10 per removed submission. Reputation is displayed on user profiles as a numeric score and tier badge (Lurker, Contributor, Trusted, Expert). High-reputation users' verifications carry greater weight in confidence score calculation. |
| FR-022 | P1 | Bulk CSV import for power users | Authenticated users with 50+ reputation can upload a CSV of compatibility data. CSV template provided with required columns: year, make, model, part_brand, part_name, fit_outcome, notes. System validates each row and presents a preview before committing. Bulk imports are reviewed by admins before public visibility. Attribution is maintained per row to the importing user. |
4.4 Price Comparison & Affiliate
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-023 | P0 | Multi-retailer price display | Part detail page shows prices from all integrated retailers sorted cheapest first. Each price row shows: retailer logo, price (USD), stock status (In Stock / Limited / Out of Stock), and a "Buy at [Retailer]" CTA. Prices are updated at minimum every 24 hours via API. Staleness indicator shown if price data is older than 48 hours. |
| FR-024 | P0 | Affiliate link generation with disclosure | All "Buy at [Retailer]" links are affiliate-tagged per retailer program requirements. Affiliate disclosure banner is displayed on every page containing affiliate links per FTC guidelines. Disclosure must read: "MotoPartPicker earns a commission from purchases made through links on this site, at no cost to you." Disclosure is visible without scrolling on desktop and mobile. Affiliate tag is never applied to links where no program relationship exists. |
| FR-025 | P0 | Sort order is price-neutral | Parts search results are sorted by confidence score descending as default. Sort options include: Confidence (default), Price: Low to High, Price: High to Low, Newest. Affiliate commission rates must not influence default sort order. This constraint is documented in the data model and must be maintained across all algorithm changes. |
| FR-026 | P1 | Affiliate click tracking | System records each affiliate click with: user_id (or anonymous session), part_id, retailer_id, timestamp, source page. Click data is stored in the AffiliateClicks entity. Monthly reports show click volume, estimated conversions (from retailer dashboards), and estimated revenue by retailer. System validates referral integrity — no self-referral inflation. |
| FR-027 | P2 | Price alert subscriptions | Authenticated users can set a price threshold alert for any part. System checks price daily and sends email notification when price at any retailer drops below threshold. Email includes: part name, new price, retailer, and direct affiliate link. User can manage alerts from account settings. Maximum 10 active alerts per free user. |
| FR-028 | P2 | Build cost calculator | Build system shows running total of all parts in the active build based on cheapest available price per part across integrated retailers. Total updates in real time as parts are added or removed. "Cheapest possible build" and "best-rated retailer build" are shown as two total options. Cost does not include tax or shipping. |
4.5 Build System
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-029 | P1 | Create and save a build | Authenticated users can create a named build associated with a garage bike. Build stores: bike, list of parts with install status (planned / installed), total estimated cost, and optional build notes. Users can have up to 10 active builds. Build data persists indefinitely until user deletion. |
| FR-030 | P1 | Public build sharing | Users can toggle a build between private and public visibility. Public builds are accessible via shareable URL (/builds/[username]/[build-slug]). Public build pages show: bike, all parts with confidence badges and prices, total cost, build notes, and a "Clone this build" CTA. Public builds are indexed by search engines. |
| FR-031 | P1 | Clone a build | Any user can clone a public build to their own account. Clone creates a new build in the user's garage with all parts copied. Clone preserves attribution to original builder. Compatibility is re-evaluated against the cloning user's bike variant — differences are flagged inline. |
| FR-032 | P1 | Build install tracking | Users can mark parts in a build as "Installed" with an optional date and verification link. Marking a part as installed prompts a mini-verification flow: confirm fit, rate install difficulty, optionally submit a full verification. Parts marked as installed contribute to the user's reputation score. |
4.6 User Accounts & Profiles
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-033 | P0 | Account creation (email + Google OAuth) | Users can register with email/password or Google OAuth. Email registration requires: email verification within 24 hours, minimum 8-character password with at least 1 number. Google OAuth uses the standard PKCE flow. Account creation triggers welcome email with onboarding checklist. New accounts have zero reputation and no garage bikes. |
| FR-034 | P0 | Anonymous browsing (no forced login) | All compatibility lookup, parts browsing, price comparison, and public build viewing are fully accessible without an account. Authentication is only required for: submitting verifications, saving builds, saving a garage, setting price alerts. Login prompts are contextual and non-blocking — they appear when the user attempts an authenticated action, not before. |
| FR-035 | P1 | Public contributor profile | Each user has a public profile at /u/[username] showing: reputation score, tier badge, bikes in garage (if public), public builds, recent verifications, and contribution count. Profile photo via avatar upload or Google OAuth photo. Users can set profile to private (hides all content except username from public). |
| FR-036 | P0 | CCPA data deletion and export | Users can request full data export (JSON) from account settings. Export is generated within 24 hours and delivered via email. Users can permanently delete their account and all associated data. Account deletion triggers hard delete of: profile, verifications, builds, garage, and AffiliateClick attribution. Deletion is irreversible and confirmation-gated with a typed "DELETE" prompt. |
| FR-037 | P1 | Email notification preferences | Users can opt in/out of: new verification on their bike model (weekly digest), response to their verification, price alert triggers, community mentions. All marketing emails include a one-click unsubscribe. Transactional emails (account verification, deletion confirmation) cannot be unsubscribed. Preference changes take effect within 24 hours. |
4.7 Retailer Partner Portal
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-038 | P1 | Retailer onboarding and catalog import | Retailers can register and submit their parts catalog via: CSV upload (ACES/PIES compatible), REST API, or manual entry. Catalog import maps retailer SKUs to MotoPartPicker Part records. Import preview shows matched vs unmatched records. Unmatched SKUs are queued for manual review. Retailers receive an import report with match rate statistics. |
| FR-039 | P1 | Real-time price and inventory API | Retailers can push price and inventory updates via a REST API (documented with OpenAPI spec). API accepts: SKU, price (USD), stock_status (in_stock / limited / out_of_stock), effective_date. Updates are processed within 15 minutes. API supports bulk batch updates (up to 1,000 SKUs per request). Rate limit: 100 requests/minute per retailer API key. |
| FR-040 | P1 | Retailer analytics dashboard | Retailer portal shows: click volume by part (daily/weekly/monthly), estimated conversion rate (from affiliate program data), top-performing parts, and parts with high community-verified fits driving traffic. Dashboard data is updated daily. Retailers can export click reports as CSV. |
| FR-041 | P2 | Fitment intelligence feed (subscription) | Subscribing retailers ($299–499/month, gated by Stripe subscription — see FR-070) receive a weekly fitment intelligence report: parts with high "does not fit" community reports for their listed bikes, parts with emerging positive fitment data, return-prediction signals. Report delivered as JSON API and optional PDF summary. Retailer can act on signals to update their fitment data or flag listings. |
| FR-042 | P3 | Manufacturer verification portal | Aftermarket manufacturers can claim their brand profile and submit official fitment data. Manufacturer-submitted records are labeled "Manufacturer Verified" (distinct from community-verified). Manufacturers must verify brand ownership. Manufacturer data is weighted highest in confidence scoring. Manufacturers cannot suppress community-reported incompatibilities — they can only add clarifying notes. |
4.8 Content & SEO
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-043 | P0 | SSR-rendered bike and part pages | All bike landing pages and part detail pages are server-side rendered or statically generated. Pages include: unique title tag, meta description, canonical URL, structured data (JSON-LD Product/Review schema). LCP <2s on mobile (3G simulated). Pages are crawlable and indexable by Googlebot. |
| FR-044 | P0 | Bike-specific landing pages | Each supported bike has a dedicated landing page at /bikes/[year]-[make]-[model] showing: verified parts count, popular builds, top community contributors for that bike, and most-recently verified parts. Pages are auto-generated from the database. Title format: "[Year Make Model] Parts — Verified Fits | MotoPartPicker." |
| FR-045 | P1 | Sitemap and robots.txt | Auto-generated XML sitemap includes all public bike pages, part pages, and public build pages. Sitemap is updated within 24 hours of new content. Robots.txt blocks: /admin, /api, user settings pages. Sitemap is submitted to Google Search Console at launch. |
| FR-046 | P2 | Community install guides | Users with 100+ reputation can create step-by-step install guides linked to a specific Part+Bike combination. Guides include: title, difficulty rating, estimated time, tool list, numbered steps with optional photos. Guides are reviewed by moderators before publication. Published guides are linked from the part detail page and indexed by search engines. |
4.9 Admin & Data Management
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-047 | P0 | Admin moderation console | Admin users can: review and action flagged verifications (approve/remove), manage user accounts (suspend/delete), add/edit bikes and parts directly, override confidence badges, and view site-wide submission queue. All admin actions are logged with timestamp and admin user ID. Admin console is behind role-based auth — not accessible to regular users. |
| FR-048 | P0 | Parts and bikes database management | Admin can: add new bikes (year/make/model/variant), add new parts (name/brand/category/description/OEM part numbers), link parts to bikes with an initial confidence level, and merge duplicate records. Bulk import via CSV for initial seeding. Changes to existing records create a version history for audit. |
| FR-049 | P1 | Site analytics dashboard | Internal dashboard (admin only) shows: daily/weekly/monthly MAU, new registrations, verifications submitted, affiliate clicks, top-searched parts, bikes with highest traffic, and community health metrics (verifications per day, flag rate). Data refreshed daily from analytics pipeline. |
| FR-050 | P2 | Automated spam detection | System applies heuristic spam detection to new verifications: rate limiting (max 10 verifications/hour/user), duplicate submission detection (same user, same part, same bike within 24 hours), bot detection via honeypot fields. Suspicious submissions are auto-flagged for review rather than auto-deleted. False positive rate <0.5%. |
4.10 Payment & Billing (Retailer Subscriptions)
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-051 | P0 | Stripe integration for retailer subscriptions | Retailer subscription billing is processed entirely through Stripe. MotoPartPicker does not store credit card numbers. Stripe Checkout handles PCI-DSS compliance. Subscription plans are managed as Stripe Products with recurring billing. Webhooks handle: subscription created, subscription cancelled, payment failed, invoice paid. Failed payments trigger a 3-attempt retry cycle before access suspension. |
| FR-052 | P0 | Subscription tier management | Two initial subscription tiers: Basic ($299/mo — fitment intelligence feed, API access) and Pro ($499/mo — all Basic plus priority support, enhanced analytics, custom reporting). Tier access is enforced via feature flags gated on Stripe subscription status. Subscription status is cached and re-validated every 15 minutes from Stripe. |
| FR-053 | P0 | No consumer payments | The rider-facing product is free with no paywalls. No consumer credit card collection. No premium features for riders behind a paywall at MVP. This constraint is a core trust mechanic — the tool must be genuinely free to compete with forum alternatives. Future premium rider features (if any) require separate BRD approval before implementation. |
| FR-054 | P1 | Billing portal and invoice management | Retailers can access a self-service billing portal (Stripe Customer Portal) to: update payment method, download invoices, upgrade/downgrade plan, and cancel subscription. Cancellation is effective at end of current billing period. Cancellation confirmation email is sent immediately. No penalties for cancellation. |
4.11 Additional Functional Requirements
| ID | Priority | Requirement | Acceptance Criteria |
|---|---|---|---|
| FR-055 | P0 | Mobile-first responsive design | All pages are fully functional and visually correct at 320px, 375px, 768px, 1024px, and 1440px viewport widths. Touch targets minimum 44x44px. No horizontal scroll on any standard viewport. Critical actions (bike selector, part search, verify fit CTA) accessible without zoom on mobile. Tested on iOS Safari and Android Chrome. |
| FR-056 | P0 | WCAG 2.1 AA accessibility | All interactive elements have visible focus indicators. Color contrast ratio minimum 4.5:1 for body text, 3:1 for large text and UI components. All images have alt text. All form inputs have associated labels. Page structure uses semantic HTML landmarks. Keyboard navigation covers all interactive flows. Screen reader tested with VoiceOver (macOS) and NVDA (Windows). |
| FR-057 | P0 | Error handling and empty states | Every list view has a defined empty state: (1) no bike data — invite contribution, (2) no search results — suggest related categories or popular parts, (3) API error — show cached data where available, display graceful error message with retry CTA. No raw error stack traces are exposed to end users. 404 page includes bike selector to redirect users toward content. |
| FR-058 | P1 | Part submission by community | Authenticated users can submit a new part that doesn't exist in the database. Submission requires: part name, brand, category, and at least one compatibility claim. Submitted parts enter a review queue. Admin reviews within 72 hours. Approved parts become publicly visible. Submitter receives +5 reputation on approval. Duplicate detection runs before submission to prevent redundant entries. |
| FR-059 | P1 | Shareable compatibility lookup URL | Every bike+category compatibility view has a stable, shareable URL that encodes the bike selection and active category filter. URL format: /bikes/[year]-[make]-[model]/[category]. Sharing the URL reproduces the identical view for the recipient without requiring login. Canonical URLs are consistent regardless of query parameter order. |
| FR-060 | P2 | Beginner guides for first mods | Curated guide pages for common first-mod scenarios (e.g., "First 5 mods for a 2020 Ninja 400"). Each guide links to verified-fit parts for the featured bike. Guides are authored by the editorial team or high-reputation contributors. Guides are indexed for SEO. Entry point from Maria-archetype outcomes ("protect my bike from drops"). |
Non-Functional Requirements
5.1 Performance
| Metric | Target | Measurement Method |
|---|---|---|
| Largest Contentful Paint (LCP) | <2.0s on mobile (3G) | Lighthouse CI in deploy pipeline; Google Search Console Core Web Vitals |
| First Input Delay (FID) / INP | <100ms | Chrome User Experience Report; Real User Monitoring |
| Cumulative Layout Shift (CLS) | <0.1 | Lighthouse CI; Web Vitals library |
| Parts search response time | <500ms p95 | Server-side APM (Fly.io metrics or Datadog); measured at 25K MAU load |
| Bike selector dropdown load | <200ms | Front-end performance test; selector data served from CDN cache |
| API response time (retailer API) | <300ms p99 | APM on API endpoints; measured under sustained load |
| Page availability (uptime) | 99.5% monthly | External uptime monitoring (UptimeRobot or Better Uptime) |
| CDN cache hit rate | >80% for static pages | CDN dashboard metrics; bike/part pages are prime candidates for caching |
5.2 Security
| Area | Requirement | Standard |
|---|---|---|
| Data in transit | All traffic over HTTPS. TLS 1.2 minimum, TLS 1.3 preferred. HSTS enforced. | OWASP Transport Layer Security Cheat Sheet |
| Data at rest | Database encryption at rest (AES-256). Passwords hashed with bcrypt (cost factor 12+) or Argon2id. | OWASP Password Storage Cheat Sheet |
| Authentication | JWT with 15-minute access token expiry + rotating refresh tokens. Rate limiting on login (5 attempts / 15 min per IP). | OWASP Authentication Cheat Sheet |
| Input validation | Server-side validation on all user inputs. Parameterized queries only — no string interpolation in SQL. XSS prevention via Content Security Policy header. | OWASP Top 10 (A03 Injection, A07 XSS) |
| File uploads | Uploaded files validated by MIME type and file signature (not extension only). Stored outside webroot with signed URL access. Malware scanning on upload (ClamAV or cloud equivalent). | OWASP File Upload Cheat Sheet |
| API security | Retailer API keys rotatable. API keys stored as hashed values server-side. Rate limiting per key. CORS restricted to allow-listed origins. | OWASP API Security Top 10 |
| Dependency management | Automated dependency scanning (Dependabot or Snyk) in CI pipeline. Critical vulnerabilities remediated within 48 hours of disclosure. | OWASP Top 10 (A06 Vulnerable Components) |
5.3 Scalability
| Stage | MAU Target | Infrastructure Requirement |
|---|---|---|
| Launch (Month 0) | 0–2,000 MAU | Single server or PaaS instance (Fly.io / Railway). Neon Postgres free tier. <$100/month infrastructure. |
| Year 1 (Month 12) | 25,000 MAU | Auto-scaling PaaS (2–4 instances). Managed Postgres with read replica. CDN for static assets. <$500/month. |
| Year 3 | 300,000 MAU | Multi-region deployment. Postgres with connection pooling (PgBouncer). Redis cache layer for compatibility queries. Full-text search index (pg_trgm or Meilisearch). <$2,000/month. |
5.4 Accessibility (WCAG 2.1 AA)
All pages must comply with WCAG 2.1 Level AA. Key requirements beyond FR-056:
- All dynamic content updates (e.g., confidence badge changes, search results) must be announced to screen readers via ARIA live regions.
- Confidence badge colors must not be the only differentiator — text labels are mandatory.
- All form error messages must be associated with their input fields via
aria-describedby. - Skip navigation link must be the first focusable element on every page.
- Session timeout warnings must give users at least 20 seconds to respond before logout.
- Accessibility audit using axe-core automated scanning must produce zero critical violations in CI.
Data Requirements
6.1 Core Data Entities
- id uuid PK
- year smallint
- make varchar
- model varchar
- variant varchar nullable
- production_start date nullable
- production_end date nullable
- region varchar (US/EU/JP)
- created_at, updated_at timestamptz
- id uuid PK
- name varchar
- brand varchar
- category enum
- description text
- oem_part_numbers varchar[]
- slug varchar unique
- submitted_by uuid FK Users
- created_at, updated_at timestamptz
- id uuid PK
- bike_id uuid FK Bikes
- part_id uuid FK Parts
- confidence_score smallint 0–100
- badge enum verified/reported/no_data
- confirm_count integer
- deny_count integer
- requires_modification boolean
- last_verified_at timestamptz
- id uuid PK
- compat_record_id uuid FK
- user_id uuid FK Users
- outcome enum fit/no_fit
- notes text nullable
- install_difficulty enum nullable
- photo_urls varchar[]
- flagged boolean
- created_at timestamptz
- id uuid PK
- user_id uuid FK Users
- bike_id uuid FK Bikes
- name varchar
- slug varchar unique
- is_public boolean
- notes text
- build_parts BuildParts[] join
- created_at, updated_at timestamptz
- id uuid PK
- username varchar unique
- email varchar unique
- password_hash varchar nullable
- auth_provider enum email/google
- reputation integer default 0
- role enum user/mod/admin
- is_public_profile boolean
- created_at timestamptz
- id uuid PK
- name varchar
- slug varchar unique
- affiliate_program varchar (CJ/Impact/etc)
- base_url varchar
- stripe_customer_id varchar nullable
- subscription_tier enum nullable
- api_key_hash varchar nullable
- id uuid PK
- user_id uuid nullable FK Users
- session_id varchar
- part_id uuid FK Parts
- retailer_id uuid FK Retailers
- source_page varchar
- clicked_at timestamptz
- bike_context uuid nullable FK Bikes
6.2 Privacy Framework
The following data governance rules apply across all entities:
- User data ownership: All data submitted by a user is owned by that user. Users can export or delete their data at any time (see FR-036).
- Verification anonymization: Users who delete their account have their verifications anonymized (user_id set to null) rather than deleted, to preserve the integrity of the compatibility database. The verification record content is retained; all personally identifying attribution is removed.
- Consent model: Explicit opt-in consent is collected at registration for: marketing emails, analytics tracking, and data use in retailer intelligence reports. Consent records stored with timestamp and version of privacy policy accepted.
- Data minimization: Only data required for platform function is collected. No third-party advertising trackers are embedded. Analytics are privacy-first (Plausible or equivalent, no Google Analytics 4 without explicit consent).
- Affiliate click attribution: AffiliateClicks records are retained for 24 months for revenue reconciliation. After 24 months, user_id is nullified and records are aggregated.
- Photo storage: User-uploaded photos are stored under a key that does not include the user's identity (UUID-based key). EXIF metadata is stripped on ingest to prevent location leakage.
Integration Requirements
Integration: Product catalog feed (CSV or API) for price/stock sync. Deep-link affiliate URL generation per product. Price data polled daily via catalog feed or Product Advertising API if available.
Fallback: If API unavailable, display "Check price at RevZilla" with affiliate-tagged deep link. Price shown as stale indicator if >48 hours since last update.
Integration: Product lookup by ASIN or keyword. Price, availability, and product title returned per API call. Rate limit: 1 req/sec (scaling to 10/sec at 10 qualified sales/month).
Note: Amazon affiliate links must comply with Associates Operating Agreement — no price display if >24 hours stale. Automated price caching required with TTL enforcement.
Flow: PKCE authorization code flow. Tokens stored server-side, not in localStorage. User's Google profile photo used as default avatar.
Account linking: If an email-registered account exists with the same email as the Google account, prompt user to link accounts on first OAuth login.
Integration: Stripe Checkout for initial subscription. Stripe Customer Portal for self-service management. Webhook handling for: checkout.session.completed, invoice.payment_succeeded, invoice.payment_failed, customer.subscription.deleted.
PCI scope: SAQ A — Stripe handles all card data. MotoPartPicker stores only Stripe Customer ID.
Integration: CSV catalog feed (updated daily). Deep-link affiliate URL per product.
Priority: P1 — target outreach within 30 days of MVP launch. High user intent match for adventure and off-road segments.
Integration: OEM part number cross-reference is a unique value — Partzilla's OEM catalog can help validate whether aftermarket parts match OEM fitment specs.
Priority: P1. Partzilla's OEM part number database has strategic value beyond affiliate revenue.
7.1 Integration SLAs
| Integration | Dependency Type | Failure Mode | Fallback |
|---|---|---|---|
| Price APIs (all retailers) | Non-critical path | Stale price displayed with timestamp | Cache last known price for 7 days |
| Google OAuth | Non-blocking (email auth available) | OAuth login fails gracefully; email login remains available | Email/password auth always available |
| Stripe | Retailer billing only | Subscription access checked from local cache; re-validated on recovery | Grace period of 24 hours before access suspension |
| Photo CDN | Non-critical for core compatibility | Photos fail gracefully with placeholder image | Placeholder displayed; retry on page reload |
MVP Scope Definition
The MVP includes all P0 requirements only. The MVP is defined as the minimal product that can be shared publicly, attract community contributors, and begin generating the data flywheel. It does not generate significant revenue — revenue is a V1.1 objective.
8.1 P0 Feature Set (MVP)
- Bike Selector: Year/Make/Model cascade covering the top 20 most-sold bikes (2018–present), prioritizing beginner bikes (Ninja 400, CB300R, MT-03, Rebel 500, R3, Duke 390).
- Parts Compatibility Lookup: Category browse and full-text search, pre-filtered to selected bike, with confidence badges (Verified / Community Reported / No Data).
- Community Verification System: Confirm/deny fit submissions with optional photos and notes. Confidence score recalculation on each submission. Moderation queue.
- Multi-Retailer Price Comparison: Prices from RevZilla, Amazon, and one additional retailer. Affiliate links with FTC-compliant disclosure. Sort by price.
- Outcome-Based Entry: Homepage and bike landing pages with outcome cards for beginners, category browse for experienced riders.
- Empty State That Converts: Informative empty states for unsupported bikes with community CTA.
- Account Creation: Email + Google OAuth. Anonymous browsing fully supported.
- Admin Console: Basic moderation and database management.
- SSR / SEO: Server-rendered bike and part pages with structured data.
- Mobile-First Responsive Design: WCAG 2.1 AA compliant.
- Retailer Billing (Stripe): Subscription infrastructure in place for V1.1 retailer partners.
8.2 Definition of Done (10 Criteria)
A feature is not "done" until all of the following criteria are met:
- All acceptance criteria defined in this BRD are implemented and verified by QA.
- Unit tests pass with >80% coverage on business logic (compatibility score calculation, affiliate link generation, confidence badge assignment).
- End-to-end test covering the primary user flow (select bike → find part → view price → click affiliate link) passes in CI.
- Lighthouse CI score: Performance >80, Accessibility >95, Best Practices >90, SEO >90 on all new pages.
- No axe-core accessibility violations at the critical or serious level.
- Feature reviewed and approved by product owner before merging to main.
- API documentation updated if any new endpoints are introduced.
- Privacy impact assessed — no new personal data collected without consent flow update.
- FTC affiliate disclosure present and visible on all pages containing affiliate links.
- Mobile tested on physical iOS and Android device (or equivalent emulator) at 375px viewport.
8.3 Explicit MVP Exclusions
- Build system (P1 — save builds requires accounts and garage, deferred to V1.1)
- Retailer API data ingestion (P1 — requires retailer partner relationships)
- User reputation system (P1 — requires sufficient community volume to be meaningful)
- Modification stacking / conflict detection (P2)
- Install guides (P2)
- Price alerts (P2)
- Anything in P3
- Consumer payments of any kind
Legal & Compliance Triage
Assumptions & Constraints
10.1 Assumptions
- 01Community will contribute fitment verifications at a sufficient rate to build useful data density within 3–6 months of launch. This is validated by the PCPartPicker precedent and Jake's explicit offer to contribute his 200-row dataset, but is not guaranteed.
- 02At least 2 major retailers (RevZilla + 1 other) will accept affiliate partnership applications within 60 days of launch. Affiliate programs are standard for these retailers, but acceptance is not guaranteed for new sites with low traffic.
- 03SEO will be the primary acquisition channel, driven by model-specific fitment queries (e.g., "2020 Ninja 400 frame sliders confirmed fit"). Search volume for these queries is sufficient to drive organic traffic without paid acquisition.
- 04The top 20 target bikes have sufficient aftermarket parts activity to populate meaningful compatibility data within the launch window. Bikes are prioritized by registered US ownership volume and aftermarket parts search volume.
- 05Motorcycle riders are willing to create accounts to contribute verifications when the platform provides clear value (finding what fits) and the contribution flow is mobile-optimized and under 60 seconds.
- 06The product can be built and operated by a 1–2 person team on under $100/month infrastructure during the zero-revenue phase, validating the lean startup model before scaling.
- 07The competitive moat (community-verified fitment database) will be difficult for a well-funded competitor to replicate quickly because the data requires community trust and contribution over time, not just capital.
- 08Affiliate commission structures at major motorcycle retailers will remain at 5–8% for at least 18 months post-launch. This assumption carries Amazon commission volatility risk (see Key Risks in Section 10.2).
- 09Google's search algorithm will continue to reward content with strong E-E-A-T signals (community-verified, specific, expert content) over thin affiliate pages, maintaining the organic traffic model.
- 10Rider communities (Reddit r/motorcycles, model-specific forums) will organically reference and link to MotoPartPicker when the tool demonstrates genuine value, providing both traffic and data validation.
10.2 Constraints
- 01Team size: MVP must be buildable by 1–2 people. Architecture and feature set must be scoped accordingly. No enterprise tooling or processes required.
- 02Budget: Infrastructure budget is <$100/month until affiliate revenue exceeds $1,000/month. Technology choices must accommodate this constraint (PaaS over custom infrastructure, managed databases over self-hosted).
- 03Data quality: MotoPartPicker cannot manufacture compatibility data. The platform is only as good as the community contributes and the retailers provide. The product design must acknowledge this transparently to users.
- 04Affiliate dependency: The primary revenue model is dependent on third-party affiliate programs that can change or terminate unilaterally (Amazon precedent: 2020 commission cuts). Retailer data subscriptions are the diversification strategy, not a near-term certainty.
- 05No exclusive data: Per Diana's constraint, retailers will not provide exclusive data or lock-in. The data strategy is additive and non-exclusive — any retailer's data improves the commons.
- 06No consumer transactions: MotoPartPicker does not process consumer payments, hold inventory, or manage logistics. This is both a scope constraint and a trust mechanism. Any deviation requires board-level approval.
- 07Technology: The tech stack (SvelteKit + Postgres per synthesis doc) must support SSR for SEO, a relational data model for compatibility queries, and a community contribution flow. Technology changes require BRD revision.
Success Criteria
The following metrics define success at three milestones. These are the canonical numbers from the synthesis document — do not generate alternate projections.
11.1 Revenue Projections (Canonical)
| Revenue Stream | Year 1 | Year 2 | Year 3 |
|---|---|---|---|
| Affiliate Revenue | $30,000 | $350,000 | $1,400,000 |
| Retailer Subscriptions | $0 | $72,000 | $216,000 |
| Total Revenue | $30,000 | $422,000 | $1,616,000 |
11.2 Leading Indicators (Monthly Monitoring)
- Data density rate: New verifications per week per active bike. Target: 5+ verifications/week/bike in Month 3. Below 2 = data strategy intervention required.
- Affiliate click-through rate: Affiliate clicks / total part detail page views. Target: 15–25%. Below 10% suggests friction in the price comparison UI.
- Return visitor rate: Users who return within 30 days of first visit. Target: 30%+. Below 20% suggests the core value proposition is not landing.
- Verification-to-account ratio: Verifications submitted per registered account. Target: 3+ lifetime verifications per account. Measures community health vs. lurker-only behavior.
- Forum citation rate: Number of external links to MotoPartPicker in motorcycle forums and subreddits (tracked via backlink monitoring). Target: 10+ organic citations in Month 3. Primary organic growth signal.
Glossary
The following terms are used throughout this document with specific, defined meanings. All product, engineering, and design conversations should use these terms consistently.