EquiTrail β Backlog Score & Time EstimatesΒΆ
Updated: 2026-06-05 Keep this file current. Mark items β when completed. Update estimates as scope changes. Win score 1β10: 10 = highest business impact (revenue, legal, retention, growth).
Legend: β
done Β· π in progress Β· blank = To Do
π New items β 2026-06-05 sessionΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #286 | Premium code generator β Admin tool (web/admin app) to create trackable PRO codes with: code name (e.g. "John-press"), max-usage count, expiry date. Tracked in Firestore promo_codes/{code}: {name, maxUses, usedCount, usedBy:[uid], createdBy, expiresAt, isActive}. User enters code in app β verifyProAccess Cloud Function validates + activates 30-day PRO. Admin sees usage in admin portal. |
2d | 9 |
| #287 | Referral tiers β Extend referral_service.dart with full tier system: 3 friends (install+active) β 1 month free; 5 friends (active accounts) β 1 month free; 5 premium referrals β Supporter badge + 6 months free PRO; 25 premium referrals β Ambassador badge + profile frame + Discord Ambassador access + extended free PRO; 50 premium referrals β Elite Ambassador + 2.5% commission; 100+ premium referrals β Sponsor Partner + 10% commission. Tracked in referrals/{uid} with type: 'install'|'active'|'premium' per referred user. | 3d | 9 |
| #288 | Referral active/premium tracking β When a referred user completes their first ride β mark as 'active' in referral doc. When referred user upgrades to PRO β mark as 'premium'. Cloud Function triggers on ride save + subscription activate. Required for tier rewards in #287. | 1d | 9 |
| #289 | Ambassador dashboard β New screen under Settings > Ambassador (only visible when role='ambassador' or higher). Shows: total referrals, active count, premium count, commission earned (if unlocked), progress to next tier, leaderboard rank vs other ambassadors. Top 3 quarterly winners get gift card/merch (tracked in Firestore). | 2d | 8 |
| #290 | Stable/club/instructor dashboard β Separate dashboard screen for accounts with role='stable'|'club'|'instructor'. Shows: how many members installed via their referral, how many converted to PRO, revenue impact. Admin can see all such accounts in admin portal. | 3d | 7 |
| β #291 | Website region subpages β 55 pages (51 regions + 4 country indexes) show real rides + OSM official routes from Firestore community_trails. Toggle map layers (routes/rides). Per-province route counts on country index pages. Shared JS module: website/js/routes-region.js. |
done | 8 |
| #292 | Trailer-friendly parking search β Add POI type 'trailer_parking' to POI service. In navigation screen search bar: "Paardentrailer parkeerplaats" option shows nearby trailer parking from Overpass API (amenity=parking + horse_trailer=yes OR from curated Hive dataset). Shows on map with horse trailer icon. | 2d | 7 |
| #293 | Arena dressage letters + course patterns β Expand ArenaScreen with: dressage arena letter overlay (A, K, E, H, C, M, B, F, D, X, G, V, P, R, S, I + 20Γ40m and 20Γ60m layouts). User can select dressage test from a list of standard Dutch proeven (Oefenklasse B, L1, L2, etc.). App shows next movement to ride. Also support non-circle patterns: serpentine (S-bocht), diagonal, half-pass, shoulder-in. Track which movements were completed and score adherence. | 5d | 7 |
| #294 | Jump height tracking β In JumpingScreen: add field for obstacle height before session. During GPS jump detection, calculate clearance = detected jump apex height - obstacle height. Show per-jump stats: obstacle height, clearance, max height reached. Session summary: average clearance, best clearance, count by height category. Store in arena_session with jumpHeights: [{height, clearance}]. | 2d | 6 |
| #295 | Ride detail delete button β Add delete button to ride_detail_screen.dart AppBar (next to share). Show confirmation dialog. Prevent accidental tap: require 2-second hold or confirmation with ride name typed. | 0.5d | 7 |
| #296 | Feed click β ride detail view β When tapping a feed post, show a slide-up sheet with: ride map trace (from trackPoints if shared, else region heatmap), stats, gait bar, horse name (no real name for privacy), photos (if shared). "GPX opvragen" button sends request to ride owner. | 1d | 8 |
| #297 | Feed photo thumbnails β Show photo thumbnails in FeedPostCard when photoUrls is non-empty. Horizontal scroll of 3 small thumbnails (80Γ80px, rounded). Tap opens full-screen gallery. Currently FeedPost.fromFirestore already reads photoUrls β just needs UI in feed_post_card.dart. |
0.5d | 7 |
| #298 | Grey screen investigate: unlock PRO β track β Reproduced: activating PRO (HIPPISCH code) and navigating to Track tab sometimes shows brief grey screen. Likely cause: proServiceProvider rebuild cascades through horsesProvider β TrackingScreen's map reinitializes. Investigate MapController lifecycle during provider cascade. | 0.5d | 8 |
| #299 | Nearby riders: requires active tracking β Users report no nearby riders despite opt-in. Root cause: publishLocation only called during active GPS tracking session. UI hint needed: "Ruiters verschijnen alleen wanneer ze actief rijden Γ©n zichtbaar zijn". Also add a test mode for admins. | 0.5d | 6 |
| #300 | Friend displayName in search results β Investigate "letters under each other" display. Likely: displayName correct in Firestore, but ListTile title is too narrow due to wide trailing widget. Fix: add maxLines:1 + overflow:ellipsis on all friend ListTile titles. | 0.5d | 7 |
| #318 | Parent Safety β Family PRO plan π PREMIUM MANDATORY β Complete parent/child safety system with child account lock. Child account restrictions (server-enforced, not bypassable client-side): GPS tracking cannot be disabled during ride Β· safety alerts locked on Β· sign-out button hidden Β· app uninstall triggers push to parent Β· all verified via Firestore family_links.parentControlled=true flag read on every launch. Parent can grant "trust unlock" per restriction individually as child matures. Core features: β Complete parent/child safety system. Parents buy PRO specifically for their child's safety β they are the paying customer. Core features: (1) Family linking β parent sends invite code to child's account; child accepts (both must consent β GDPR compliant). Child sees "π Bewaakt door {naam}" indicator at all times (transparency, no secret tracking). (2) Parent safety dashboard β dedicated screen showing all linked children: live location (during active session only), last seen, current ride distance/duration, battery level. (3) Ride start/end push notification β parent gets: "Emma is begonnen met rijden π΄" + map pin, and "Emma heeft haar rit gestopt β
8.4 km in 52 min". (4) No-movement alert (#312) auto-routes to parent β if child stopped for >5 min without pausing β parent gets SMS/push before anyone else. (5) Fall detection (#313) auto-routes to parent. (6) Geofence / safe zone β parent draws a zone (e.g. around stable). If child rides outside: parent alerted immediately with map link. Radius: 0.5β50 km adjustable. (7) Expected return time β child sets "Ik ben terug om 17:00" before ride. If not returned: parent alerted at 17:05 with GPS. (8) Family PRO plan β new pricing tier: 1 parent + up to 3 children under one subscription. Pricing: β¬15/mo Β· β¬130/yr Β· Store: β¬149.99/yr (save β¬50/yr vs monthly β "meer dan 2 maanden gratis"). Child accounts get full PRO features included. (9) GDPR compliance β ages 13-15 (NL GDPR Art 8): parental consent required at registration. Under 13: guardian account required. Child can end monitoring link at age 16. Consent stored in Firestore with timestamp. (10) Admin visibility β admin can see all family links for support/abuse prevention. Firestore schema: family_links/{linkId} {parentUid, childUid, status: 'pending'|'active', consentAt, geofences: [{lat,lng,radiusKm,name}], notifyOnStart: bool, notifyOnStop: bool, expectedReturnAt: Timestamp}. Why this converts: parents are the ones paying for horses anyway. "You let your 14-year-old ride alone in the fields β for β¬15/month you always know where she is." Emotional purchase, zero price resistance. |
4d | 10 |
| #322 | App themes / UI skins β Beyond dark/light mode: full color theme skins that change the app's accent colour, gradient backgrounds, card styles and button colours. Free themes (3): Default Green (current) Β· Ocean Blue (calm blues and teals) Β· Warm Sand (earthy warm tones). PRO themes (5+): Midnight Purple Β· Rose Gold Β· Forest Dark Β· Lavender Dream Β· Golden Hour. Seasonal themes (auto-applied, admin-toggled, see #321): Sinterklaas Red Β· Christmas Snow Β· King's Day Orange. Implementation: settingsThemeKey in Hive currently stores 'system'/'light'/'dark'. Extend to include theme skin ID. MaterialApp wraps everything with ThemeData β skin changes the colorScheme.primary, colorScheme.secondary, gradient colors used throughout. Theme preview thumbnails shown in Settings > Uiterlijk as small app mockup cards (like image #13). Skin stored in Hive + synced to Firestore. Live preview: tap a theme β app instantly updates without restart. |
2d | 8 |
| #323 | In-app avatar companion β Cute animal avatar displayed on the home screen (top-right corner, replaces or overlays the profile photo area) and on the profile screen. Acts as a visual companion that users identify with and want to collect. Horse avatars (primary β all breeds, styles): π΄ Classic brown horse (free, default) Β· π΄ White stallion (free) Β· π΄ Black beauty (PRO) Β· π΄ Friesian horse (PRO β unlock for 50 km badge) Β· π΄ Spotted pinto (PRO) Β· π΄ Unicorn π¦ (PRO β most wanted!) Β· π΄ Golden palomino (PRO). Cute animal companions (secondary): π± Black cat (free) Β· π° Pink bunny (free) Β· π¦ Fox (PRO) Β· π¨ Koala (PRO) Β· π§ Penguin (PRO) Β· πΌ Panda (PRO) Β· πΈ Frog (PRO) Β· π¦ Hedgehog (PRO) Β· πΆ Corgi (PRO). Badge-unlocked avatars (earn them by riding): Night Owl π¦ (unlock via hidden_nachtuil badge) Β· Rain Dancer π§οΈ frog (unlock via hidden_regendanser badge) Β· Beach Seahorse π (unlock via strandruiter badge) Β· Forest Deer π² (unlock via bosverkenner badge) Β· Arctic Penguin ποΈ (unlock via 1000 km badge) Β· Galloping champion horse (unlock via five_thousand_km badge). Avatar picker screen: 3-column grid like screenshots. Lock icon π on premium avatars. Pink "Nieuw" badge on new additions. Silhouette shown for unearned badge-unlock avatars (visible but greyed, shows what badge unlocks it β motivation to ride). Avatar display: 80Γ80px on home screen top-right, subtle idle animation (gentle breathing/ear flick β Lottie JSON, <50KB each). Tap avatar on home β opens avatar picker. Storage: selected avatar ID in Hive settingsAvatarKey + Firestore users/{uid}.avatarId. Avatar definitions stored in Firestore app_config/avatars (admin can add new ones without app update). PRO gate: attempt to select locked avatar β bottom sheet "Upgrade naar PRO om dit dier vrij te spelen π" Β· OR shows which badge to earn for badge-locked avatars. Asset strategy: Use emoji-style flat vector SVG/PNG assets (licence-free, included in assets/avatars/ folder). No 3D β flat kawaii style like the screenshots. Start with 15 avatars, grow the collection as engagement data comes in. |
3d | 10 |
| #320 | Seasonal promotions β Black Friday, Cyber Monday, Christmas β Annual promotional calendar with time-limited PRO discounts. Black Friday (last Friday of November): 30% off annual PRO Single + Family PRO β 72-hour window. In-app banner + website homepage banner + email to free users + Discord announcement. Cyber Monday (Monday after Black Friday): 20% off monthly PRO β 24-hour window only. Positioned as "last chance" for those who missed Black Friday. Christmas / Sinterklaas: "Geef PRO cadeau" β gift subscription flow: buyer pays, receives a gift code (1 month or 1 year), gives code to recipient who redeems on first login. Runs 1β24 December. Special Christmas-themed share card and email template. Technical: promo codes generated via admin (backlog #286) Β· Stripe coupon IDs stored per promotion Β· Cloud Function validates codes at checkout Β· admin dashboard shows promo redemption stats Β· codes expire 48h after campaign end. | 2d | 9 |
| #321 | Seasonal themes in app β Time-based visual theme overlays for special occasions. Sinterklaas (1β5 Dec): horse avatar gets pepernoten bag accessory, app accent colour shifts to red/gold, achievement badges get Sinterklaas hats. Christmas (15β27 Dec): snow particles on home screen, horse avatar gets reindeer antlers, "Fijne Feestdagen" greeting card on first open. New Year (31 Decβ1 Jan): fireworks animation on achievements unlocked during these dates, confetti on home screen midnight trigger. Spring (21 Marβ21 Jun): optional β flower crown on horse avatar, lighter greens. Easter (date-based): Easter egg hunt mini-game β hidden badge unlocked by tapping a hidden Easter egg in the app 3Γ (appears in a random spot each year). King's Day NL (27 Apr): orange accent. Implementation: Theme config stored in Firestore app_config/seasonal_themes β admin enables/disables each theme remotely without an app update. App polls on launch (cached 6h). All animations lightweight (Lottie JSON). Themes are cosmetic only β no functional changes. |
3d | 7 |
| #319 | Family PRO β abuse prevention + 4+ children scaling β (1) Age gate: child's registered birth year must make them β€17 at link time β system silently rejects adult accounts. (2) One family per child: single parent per child β cannot be in two families. (3) 48h invite tokens: one-time codes, expire 48h, single-use. (4) GPS overlap soft check: Cloud Function at day 30 β flag if parent + child never within 10km, admin reviews. (5) Fraud admin dashboard: auto-flags plans with children spanning 3+ provinces, all created same hour, or zero rides in 60 days. (6) ToS clause: subscription terminated without refund on confirmed fraud. (7) 4+ children pricing β simple +β¬3/child, no tiers: 3 kids = β¬15/mo (β¬130/yr) Β· 4 kids = β¬18/mo (β¬155/yr) Β· 5 kids = β¬21/mo (β¬180/yr). In-app when adding 4th child: single button "Extra kind toevoegen β +β¬3/mnd". (8) 6+ children = support ticket only: must provide birth certificates / BRP uittreksel proof β admin activates manually. Nobody fakes 6 kids for β¬3/month. | 2d | 9 |
| #317 | Conversion triggers β in-app FOMO & upgrade hooks β Smart contextual PRO prompts shown at the highest-value moments: (1) Safety trigger β after any ride > 5km from nearest road without a friend β bottom sheet: "Je reed alleen in een afgelegen gebied. Val-detectie & noodcontact zijn beschikbaar in PRO." (2) History trigger β at day 85 β banner in Ride History: "Je oudste ritten verdwijnen over 5 dagen uit je overzicht. Upgrade om ze te bewaren." (3) Coaching trigger β after 10 rides, if gait asymmetry detected (>65% one direction) β "Onze analyse toont 72% rechtshandig rijden. De PRO-houdingscoach helpt dit corrigeren." (4) Badge trigger β when within 5% of a milestone badge β "Nog 3 km voor je 100 km badge β PRO-ruiters ontvangen een deelbare mijlpaal-kaart." (5) Horse limit trigger β when user tries to add 2nd horse β "Upgrade voor onbeperkte paarden." (6) Export trigger β on 4th GPX export of the month β "Je hebt je 3 gratis exports gebruikt β PRO geeft onbeperkt exporteren." All triggers: one-time per category (not spammy), dismissable, track dismiss count in Hive. | 2d | 10 |
| #316 | Free tier redesign β FOMO funnel β Change free limits from 5 rides to: (1) Basic tracking fully unlimited β every ride saves forever. (2) Ride HISTORY view limited to last 90 days (free) vs all-time (PRO). (3) Horses still limited to 1 free / unlimited PRO. (4) GPX export limited to 3 per month (free) / unlimited PRO. (5) Conversion triggers: at 90-day mark β "Je hebt 3 maanden ritten β upgrade om je volledige geschiedenis te bewaren" Β· near a badge milestone β PRO coaching upsell Β· after first remote solo ride β safety alert upsell. Code changes: AppConstants.freeMaxRides removed, replaced with freeHistoryDays = 90. ridesProvider filters by date for free users instead of count. RideHistoryScreen shows a "π Upgrade voor oudere ritten" banner when free user scrolls past 90-day cutoff. |
1d | 10 |
| #315 | Data protection & bot prevention β GPX files and ride data must never be scrape-accessible from website. (1) All Firestore feed/rides readable ONLY by signed-in users β no public reads of GPS track points or GPX data. (2) Website route pages show aggregated stats + start-pin only β no raw trackpoint coordinates in HTML/JS. (3) GPX export via app only, requires auth. (4) GPX sharing rate limit: max 10 GPX exports per user per 24h (Cloud Function check), prevents bot/scraper accounts. (5) CloudFlare WAF rule (#259) to block non-browser User-Agents on /routes/ pages. (6) honeypot hidden link in HTML to catch scrapers. (7) robots.txt Disallow: /routes/*/data β allow SEO crawlers on page, block data endpoints. Goal: build the ecosystem advantage β all the good route data is only accessible inside the EquiTrail app/account. | 1d | 9 |
| #312 | Safety: no-movement auto-alert β During an active GPS session, if the rider's speed drops below 1 km/h for more than 5 minutes WITHOUT pressing Pause, trigger a safety check. Flow: (1) Phone vibrates + shows countdown "Alles goed? Annuleer binnen 30 sec" (2) If not cancelled β send emergency contact an SMS/email with: rider name, GPS coordinates, Google Maps link, timestamp, "Geen beweging gedetecteerd". Emergency contacts are managed in app Settings > Veiligheid (name + phone + email, up to 3 contacts). Also alert when GPS goes offline (phone off/dead) for >10 min during active session. Cloud Function sends the alert so it works even if phone is locked. | 2d | 10 |
| #313 | Safety: fall detection β Detect a fall using the phone's accelerometer. Fall signature: sudden G-force spike > 3g on any axis (impact), followed by near-zero motion for > 15 seconds AND session not paused. False-positive guard: 1-minute grace period where user can dismiss ("Niet gevallen - annuleer"). If not dismissed β same alert flow as #312. Display fall count per session in the stats. Adjust sensitivity via Settings > Veiligheid > Valgevoeligheid (Low/Medium/High). Note: phone must be on the rider's body (not saddle bag) for accurate fall detection. Add guidance on recommended phone placement. | 2d | 10 |
| #314 | Posture coach β asymmetric rein / turn detection β Analyse GPS track during a session for left/right turning bias. Algorithm: count directional changes >15Β° left vs right, calculate asymmetry score (0=balanced, 100=one-sided). V1 (GPS only): at session end, show "Rij-analyse: 68% rechts β controleer je linker teugel/zit". V2 (accelerometer): if phone worn on body, detect chronic lateral tilt bias during session (rider sitting crookedly). V3 (wearable): wrist IMU from Galaxy Watch gives direct hand/wrist asymmetry β most accurate. PRO feature. Show per-session and trend over multiple sessions. Clinically this is a known technique (equine sports science uses similar asymmetry metrics). | 3d | 8 |
| #324 | Hazard confirmation β Waze-style "still there / gone" β When a rider passes within 200m of a reported hazard during an active ride, show a dismissable bottom banner: "β οΈ Gevallen boom gemeld nabij. Nog aanwezig?" with two buttons: β
"Ja, nog daar" (confirms, resets expiry) Β· β "Weg, verwijder" (marks as resolved, removes from map). After 3 "gone" confirmations from different riders the hazard auto-deletes. After 7 days with no confirmation the hazard auto-expires. POI custom report: same mechanic for user-added POIs (watering points etc.) β "Nog aanwezig?" prompt when passing. Admin can force-delete from admin app. Firestore: add confirmations: [], goneVotes: int, lastConfirmedAt: Timestamp, expiresAt: Timestamp to hazards/{id}. Cloud Function: daily job removes expired hazards. |
1d | 8 |
| π #325 | Auto-name completed rides β Cloud Function reverse-geocodes start point β generates "Rit in de Veluwe β 12 km". Scaffolded: functions/src/auto_name_rides.ts. App: FeedPost.displayTitle getter prefers autoTitle. Pending: deploy Cloud Function, test on rides. | 0.5d left | 8 |
| π #326 | More route data sources β Phase 1 β Phase 2 β³ β (1) β OSM bridleways β scripts/import_osm_bridleways.py ready; bulk pre-import per region. (2) β Toerisme Vlaanderen β scripts/import_toerisme_vlaanderen.py ready; Flanders horse routes via WFS. (3) β Staatsbosbeheer β scripts/import_staatsbosbeheer.py ready; NL forestry GPX. (4) β³ Routedatabank β email jrietman@wandelnet.nl pending; official NL routes via WFS (most valuable source). Expected Phase 1: +2000 routes; Phase 2: +5000 routes. Total: 10,000+ across NL/BE/DE/FR. | 1d now + 1d after Routedatabank | 8 |
| #311 | "Find riders" public directory β Opt-in page at equitrail.horse/ruiters/ showing riders who have enabled public discovery. Each rider card: nickname (no real name), province/region, horse count, total km, badges. Filter by province. "Vriendverzoek sturen" button β deep links to app. App setting: "Toon mij in de online ruiters-directory" (default off). Firestore: public_riders/{uid} collection with only nickname, province, stats, badges. GDPR: explicit opt-in, deletable on demand. |
2d | 8 |
| #307 | Ambassador / referral dashboard website page β Public-facing page at equitrail.horse/ambassadors/ showing: leaderboard of top referrers (anonymised, or named with consent), how the referral program works (tiers: 5 active premium β Supporter badge; 25 β Ambassador; 50 β Elite; 100 β Sponsor Partner), rewards per tier, apply/join button. Admin panel in macOS admin app shows all ambassador stats: installs, conversions, commission earned. |
2d | 8 |
| #308 | "Send to app" from website route pages β Button on each route/province page to open the route in the EquiTrail app. Android: deep link equitrail://route?lat={lat}&lng={lng}&zoom={zoom}. iOS: universal link. When app not installed: redirects to Play Store / App Store. Backend: register deep link handler in router.dart. Requires app update AND website update. |
1d | 7 |
| #309 | Endurance riding tracking β New tracking mode alongside GPS/Arena/Jumping. Endurance-specific features: heart rate zones (manual entry or BLE sensor), pace zones, cumulative altitude, mandatory rest point marking with vet check data (pulse/respiration), FEI endurance phases (pre-ride, loops 1-4, finish). TREC and CTR (Competitive Trail Riding) variants. Reports match endurance rulebooks. | 4d | 9 |
| #310 | Wearable expansion roadmap β Beyond Galaxy Watch: investigate Garmin Connect IQ (large equestrian user base), Fitbit (rebranded as Google Pixel Watch), Pebble successors (rebranded Rebble). Each needs platform SDK. Priority: Garmin Connect IQ (most popular with equestrian athletes). Document approach in docs/watch_app.md. | 1d planning | 7 |
| #305 | Horse stats dashboard per horse β Each horse card/detail shows: total km ridden on that horse, gait distribution (walk/trot/gallop %), calorie burn, number of rides, longest ride, favorite gait. If horse is used for jumping: jump count, avg/max height, personal bests. If used for arena/indoor: circle count, best session, gait balance score. Horse page tabs: "Statistieken", "Ritten", "Springen" (if relevant), "Arena" (if relevant). | 2d | 8 |
| #306 | Horse selection during ride β Before starting a GPS/arena/jumping session, rider selects which horse they're riding from their horse list (or "geen specifiek paard"). Selection shown on tracking screen. Stored with ride so stats are attributed to correct horse. Currently selection exists but no clear UX flow at session start. | 1d | 8 |
| #302 | Profile photo in leaderboard & ranking β Profile photo URL (users/{uid}.photoUrl) is not included in leaderboard docs or ranking display. Fix: when writing to leaderboard collection, include photoUrl. In the leaderboard screen widget, show CircleAvatar with NetworkImage if URL available. Same for social feed author avatar β currently shows first letter only. |
0.5d | 8 |
| #303 | Horse breed autocomplete β When adding/editing a horse, breed field shows a searchable dropdown with 200+ horse breeds in NL/EN/DE/FR (Appaloosa, KWPN, Friesian, Arabian, etc.). Case-insensitive, fuzzy match. Uses a curated local JSON list (no API needed). | 1d | 6 |
| #304 | External route importer β Scraper/Cloud Function to import GPX routes from equestrian route databases (e.g. hartvanlimburg.nl/en/bridleways-limburg). Stores in community_trails collection with attribution. Runs as scheduled Cloud Function (weekly). Expands database without user effort. Legal: only import publicly licensed routes. |
2d | 8 |
| #301 | Admin feature flag control β Remote Firestore config document app_config/feature_flags controls which features are Free/PRO/Hidden per user type. Admin toggle in macOS admin app (and/or Firebase Console) to change freeβPRO assignment for any feature. Hidden features exist in code but are invisible until unlocked β PRO users can preview "coming soon" teasers. Real-time: app listens to config doc via Firestore stream. Schema: {features: {arena: 'pro', jumping: 'pro', nearby_riders: 'free', feed: 'free', ...}, hiddenFeatures: ['dressage_letters', 'jump_height'], proTeaserMessage: 'Binnenkort...' }. Admin macOS app gets a "Feature Flags" tab with toggles. Gives fine-grained control to monetize/reward/experiment without a new release. |
2d | 9 |
π° Revenue & PaymentsΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| π #83 | Stripe website payments (β¬10/mnd, 0% commission) | 2d | 10 |
| π #84 | Google Play Billing (in_app_purchase plugin + receipt verification) | 3d | 9 |
| π #85 | App Store IAP (after Apple enrollment) | 3d | 9 |
| #102 | π΄ Shared Rider PRO β Multiple riders on one horse under one subscription. Pricing: β¬15/mo Β· β¬130/yr Β· Store: β¬149.99/yr (save β¬50/yr vs monthly). One payment by horse owner unlocks full PRO for all linked co-riders. Features: ride stats per rider (same horse, separate profiles β km, gait, calories per person) Β· shared horse health log (vet, farrier, notes visible to all) Β· shared ride calendar (who rides when, prevent double-booking) Β· horse training log (all sessions by all riders combined). Target: stable owners with shared lesson horses (β¬130/yr Γ 10 horses = β¬1,300/yr from one stable), families sharing a horse, riding schools. Firestore: horse_subscriptions/{horseId} {ownerUid, linkedRiderUids:[], planType:'shared_rider_pro', validUntil, stripeSubscriptionId}. |
4d | 8 |
| #17 | Replace manual Firestore PRO activation with Play Billing | 1d | 7 |
| #18 | App Store IAP β same scope as #85, merge | 1h | 3 |
| #87 | Document full free vs PRO feature list (website + app) | 4h | 5 |
| #1 | Payment options page (overlaps #83β85, low added value) | 4h | 4 |
π± iOS & AppleΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #35 | Enroll in Apple Developer Program (β¬99/yr β admin task) | 2h | 10 |
| #36 | Install EquiTrail on iPhone SE via flutter run | 1h | 6 |
| #41 | TestFlight: first external iOS build after enrollment | 4h | 9 |
| #32 | Submit EquiTrail to App Store | 1d | 9 |
| #42 | iOS APNs push notifications (friend requests, ride reactions) | 2d | 7 |
| #23 | Apple DeviceCheck (iOS equivalent of Play Integrity) | 1d | 5 |
| #20 | Apple Watch companion app (watchOS target in Xcode) | 2w | 6 |
β Galaxy Watch (POST-LAUNCH β deprioritised)ΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| β #188 | CRITICAL: Galaxy Watch crash loop β 3 bugs fixed, v1050 wear:internal | done | 10 |
| #33 | Confirm Galaxy Watch update to v1050 + physical watch test | 30m | 4 |
| #21 | Galaxy Watch: heart rate display in PRO mode | 2d | 4 |
π§ͺ Launch Test Plan & AutomationΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| π #213 | Launch test plan β docs/test_plan.md (functional, UX, regression, platform) | done | 9 |
| π #214 | Automated integration test suite β 18 tests, all screens, bug detection, Azure DevOps auto-issues | done | 9 |
π΄ Core App FeaturesΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #22 | Push notifications β FCM (friend requests, badges, club activity) | 3d | 9 |
| #94 | Full ride history on website (logged in, Firestore-backed) | 3d | 8 |
| β #93 | Hidden badges: isHidden field, ??? render, 5 badges (Nachtuil/Regen/Carrousel/Hollander/Veteraan) | done | 8 |
| β #40 | Friend request in-app notification β Firestore notifications collection + notificationsStream + tab badge | done | 7 |
| β #89 | GPX request from feed β requestGpx(), 3-dot menu "Vraag GPX-bestand", owner in-app notification | done | 6 |
| π #106 | Automated test plan β integration_test/app_test.dart + scripts/run_tests.sh + docs/bugtracker.md | 2d | 8 |
| #90 | Clubs: group chat with emoticons (no media) | 5d | 6 |
| #30 | Improve jump detection accuracy with accelerometer | 3d | 5 |
πΊοΈ NavigationΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #101 | Routing server fallback (OSRM secondary when GH down) | 1d | 7 |
| #25 | Belgium + Germany full routing graph merge | 2d | 6 |
| #26 | France OSM merge | 1d | 5 |
π Social & CommunityΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| β #104 | Block/report: blockUser/unblockUser, feed filter, report sheet, auto-hide @3, blocked users settings screen | done | 9 |
| #27 | Custom friend groups with names | 2d | 5 |
| #28 | Group feed filtered to club/friends | 1d | 5 |
| β #91 | Photo moderation: Discord #photo-moderation + webhook + /delete-post + /gdpr-request | done | 6 |
π€ Discord & BotΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #88 | Support Bot: auto-create tickets from #bug-reports + #feature-requests | 1d | 7 |
| #69 | Sync app badges/roles to Discord via OAuth | 3d | 6 |
| #68 | Discord: route lookup + GPX delivery (mostly done via RouteHelper) | 4h | 5 |
πΈ Media & IPΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| β #103 | Health & medical disclaimer β ToS all 4 langs | done | 9 |
| β #100 | Social media watermark + branded card on photo share (PhotoService) | done | 7 |
| β #99 | EXIF metadata on ride photos (EquiTrail software, artist, datetime, GPS comment) | done | 5 |
| β #91 | Photo moderation: Discord #photo-moderation channel + webhook + /delete-post + /gdpr-request | done | 6 |
| β #92 | IP protection β copyright headers + Terms of Service | done | 8 |
βοΈ Legal & ComplianceΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| β #105 | Account & data deletion request page (equitrail.horse/delete-account) | done | 10 |
| β #94 | equitrail.horse/history β Firebase Auth, Firestore rides, Leaflet maps, GPX export | done | 8 |
| β #104 | Block/report: blockUser/unblockUser, feed filter, report sheet, auto-hide @3, blocked users settings screen | done | 9 |
| β #103 | Health & medical disclaimer β ToS all 4 languages | done | 9 |
| β #92 | IP protection β copyright headers + Terms of Service | done | 8 |
π IntegrationsΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #137 | Fix Firestore Admin SDK 403 β firestore.googleapis.com SERVICE_DISABLED despite being enabled in console. Code ready in get_firestore_stats(). Dashboard shows N/A until fixed. |
1h | 6 |
π‘οΈ Ops & AdminΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| β #96 | Disaster recovery plan + quarterly DR test | done | 9 |
| β #97 | Comprehensive backup plan (code + secrets) | done | 9 |
| β #98 | Client media backup β GCS bucket + lifecycle + setup script | done | 8 |
| β #95 | Admin dashboard CLI + web | done | 7 |
| #24 | Certificate pinning on API calls | 1d | 5 |
π§ Support SystemΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #49 | AI bot on equitrail.horse (Claude Haiku, NL/EN/FR/DE) | 2d | 8 |
| #50 | AI bot: knowledge base from docs/ (RAG pipeline) | 2d | 7 |
| #51 | AI bot: escalate to ticket with conversation context | 1d | 7 |
| #52 | Support portal: setup support.equitrail.horse | 1d | 6 |
| #53 | Support portal: knowledge base articles (NL/EN/FR/DE) | 2d | 6 |
| #54 | Support portal: ticket system + AI pre-screening | 3d | 7 |
| #55 | Support portal: admin ticket queue + reply UI | 2d | 6 |
π Admin PanelΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| β #215 | Admin panel β users, PRO, badges, moderation, GDPR, routes map | done | 8 |
Design: separate subdomain (admin.equitrail.horse) or Oracle Docker behind Tailscale (not on main site β less public target). Firebase Auth gate (admin-only). Features: user search/edit, grant PRO, approve badges, photo moderation queue, GDPR deletion requests, install stats.
π Website IntelligenceΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| β #107 | Geo-language detection β ipapi.co, cached 24h, manual override, all pages via nav.js | done | 7 |
πͺ Store Assets & MarketingΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #56 | Play Store: screenshots all sizes NL/EN/FR/DE | 2d | 8 |
| #57 | Play Store: descriptions + ASO keywords NL/EN/FR/DE | 1d | 8 |
| #58 | Play Store: feature graphic 1024Γ500 + icon review | 4h | 6 |
| #59 | App Store: screenshots NL/EN/FR/DE (6.7", 5.5", iPad) | 2d | 8 |
| #60 | App Store: title, subtitle, keywords, categories | 1d | 7 |
| #61 | App Preview video (30 sec) | 3d | 7 |
| β #29 | equitrail.horse/riders β rider discovery landing page with real Veluwe Leaflet map | done | 6 |
| β #87 | Free vs PRO comparison table + updated feature cards + pricing fixes in index.html | done | 5 |
| #70 | Create Facebook, X, Instagram, TikTok profiles | 4h | 6 |
π AI Social Media AutomationΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #71 | Detect new public rides with photos β content queue | 2d | 6 |
| #72 | Generate Reels/Shorts from GPS track animation | 5d | 7 |
| #73 | Generate captions + hashtags via Claude API | 1d | 7 |
| #74 | Auto-post to Facebook, X, Instagram, TikTok | 2d | 6 |
π¬ Newsletter & Email MarketingΒΆ
Recommended service: Brevo (brevo.com) β EU-based (FR), GDPR native, free up to 300 emails/day. At scale (>5k subs): migrate to self-hosted Listmonk on Oracle server. Sending infrastructure: Brevo SMTP or Amazon SES (β¬0.10/1000 emails). All opt-ins must be explicit double opt-in per GDPR Art. 7. Never purchased lists.
| # | Item | Est. | Win |
|---|---|---|---|
| #241 | Newsletter opt-in β app Settings + website footer; store consent + timestamp in Firestore users.newsletterOptIn, newsletterOptInAt, newsletterRegion, newsletterPrefs |
S (1d) | 8 |
| #242 | Brevo account setup β create account at brevo.com, add DPA, connect equitrail.horse sending domain (SPF/DKIM), verify sender nossiej@... or newsletter@equitrail.horse | XS (2h) | 8 |
| #243 | Newsletter preferences centre β page at equitrail.horse/newsletter: manage frequency (weekly/bi-weekly), topics (tips/ritten/regionaal), one-click unsubscribe; update Firestore + Brevo contact | S (1d) | 7 |
| #244 | Newsletter generator script β scripts/generate_newsletter.py: pulls top community_trails by region, app changelog, riding tips from KB, regional rider stats; generates responsive HTML using Brevo template API; sends via Brevo API |
M (2β3d) | 9 |
| #245 | Weekly newsletter content β auto-generated sections: πΊοΈ Top gedeelde routes in jouw regio Β· π Toprijders leaderboard Β· π‘ Rijderstip van de week Β· π Nieuw in EquiTrail Β· β Review-verzoek (Play Store / App Store) | M (2d content + automation) | 9 |
| #246 | Review request in newsletter footer β every newsletter includes: "Vind je EquiTrail handig? Laat een recensie achter op [Play Store / App Store]" with correct store link per platform (stored in user profile); GDPR note | XS (2h) | 9 |
| #247 | GDPR compliance β unsubscribe link in every email (one-click), EU data residency confirmed, consent audit log, DPA with Brevo, privacy policy update | S (0.5d) | 10 |
| #248 | Transactional integration β after support ticket resolved: 2 days later send follow-up with review request; after 3 months PRO: retention email with new features; all conditional on newsletterOptIn |
M (2d) | 7 |
| #249 | Region segmentation β derive region from Firestore user location or GPS cluster; tag contacts in Brevo with region (Noord-Holland, Gelderland etc.); send region-specific ride highlights |
M (2β3d) | 8 |
| #250 | Listmonk migration (future) β self-host on Oracle when > 5k subs; import from Brevo; own domain tracking | L (1w) | 6 |
Newsletter content sections (#244/#245 detail)ΒΆ
Each newsletter contains:
- π Ruiter van de week β spotlight on a rider who opts in via in-app prompt or website form. Short bio, best route, horse name. Requires: opt-in form in app/website, admin approval flow. Tag: newsletterSpotlight: true in Firestore.
- πΊοΈ Route van de maand β top community trail by likes/shares in the past month, per region. Auto-pulled from community_trails orderBy likes desc. GPX download link included.
- π‘ Rijderstip van de week β rotating from KB articles (gps-tracking.html, horses.html etc.), written in friendly NL tone.
- π Jouw statistieken deze maand β personalised section: km gereden, best rit, badge unlocked. Requires: merge tag support in Brevo.
- π Nieuw in de app β curated from CHANGELOG.md, simplified for non-technical readers.
- β Laat een recensie achter β "Help ons groeien: {Play Store link / App Store link}" β platform-aware based on platform field in user doc.
- π© Wil jij featured worden? β CTA: "Ben jij onze volgende Ruiter van de Week? Mail je verhaal naar spotlight@equitrail.horse"
Implementation order:ΒΆ
- #247 GDPR policy update (prerequisite for everything)
- #242 Brevo setup (2h)
- #241 Opt-in in app + website
- #243 Preferences centre
- #244 + #245 Generator + content (including spotlight, route of month)
- #246 Review request footer
- #248 + #249 Advanced automation
ποΈ Misc / Early backlog (low priority, overlap with above)ΒΆ
| # | Item | Est. | Win |
|---|---|---|---|
| #2 | Add bonus ideas (vague β merge into relevant items) | β | 2 |
| #3 | Referral bonus (ET-code system exists, extend only) | 1d | 5 |
| #4 | Promo / act-now pages on website | 1d | 4 |
| #5 | Campaigns system | 3d | 4 |
π Top priorities (not yet started, sorted by win)ΒΆ
| Rank | # | Why |
|---|---|---|
| 1 | #35 Apple Developer enrollment | Unlocks #32, #41, #42, #85 β entire iOS track blocked on this |
| 2 | #33 Test Galaxy Watch install | 2 hours, potentially marks watch as live in production |
| 3 | #98 Firebase Storage β GCS backup | 4 hours, protects all user photos permanently |
| 4 | #56/#57 Play Store screenshots + ASO | Direct install growth, no proper store presence yet |
| 5 | #88 Discord support bot | 1 day, saves hours of manual support per week |
ποΈ Infrastructure Scaling β Growth Readiness PlanΒΆ
Principle: No vendor lock-in at the data layer. Firebase Auth + Firestore are fine for launch, but the rides/tracks data must remain portable. Build with abstraction layers from day 1. Current stack review date: 2026-06-04. Re-evaluate at each phase threshold.
Current stack (Phase 1 β 0β2,000 users)ΒΆ
| Component | Service | Cost | Vendor risk |
|---|---|---|---|
| Database | Firebase Firestore (europe-west4) | Free tier | Medium β mitigatable |
| Auth | Firebase Auth | Free tier | Low β OAuth2 standard |
| File storage | Firebase Storage | Free tier | Medium β use signed URLs |
| App hosting | Plesk (equitrail.horse) | ~β¬20/mo | Low β easy to move |
| Backend services | Oracle Cloud ARM (free tier) | β¬0 | Low β Docker, portable |
| Office 365 shared mailbox | existing | Low β SMTP replaceable | |
| CDN | None yet | β¬0 | N/A |
Phase thresholds and actionsΒΆ
| # | Item | Trigger | Est. | Win |
|---|---|---|---|---|
| #251 | Phase 2 prep (2kβ10k users) β Enable Firebase Blaze billing, set spend alerts at β¬50/β¬100/β¬200, monitor Firestore reads/writes/Storage daily. Add Cloudflare free CDN in front of equitrail.horse. Expected Firebase cost: β¬20β80/month | 1,500 active users | S (1d) | 7 |
| #252 | Firestore cost optimisation β GPS tracks stored as compressed JSON blobs (already done). Add Firestore TTL on active_riders (2h), rider_discovery (24h). Batch writes for ride saves (reduce write count 60β80%). Cache leaderboard in Firestore (not real-time). |
5k rides/month | M (2d) | 9 |
| #253 | Phase 3: PostgreSQL for rides (10kβ50k users) β Rides data (GPS tracks, stats) migrated from Firestore to managed PostgreSQL (Supabase europe-west or Neon.tech serverless). Firestore remains for social/feed/settings (fits its NoSQL strength). Migration path: dual-write β backfill β cutover. Ride data is structured = major cost saving. Estimate: Firestore rides cost β¬300/mo at 50k users vs β¬30 PostgreSQL | 10,000 registered users OR Firestore bill > β¬100/mo | XL (2w) | 10 |
| #254 | Firebase Storage β Cloudflare R2 β Photo storage migrated to Cloudflare R2 (zero egress fees, S3-compatible API). Firebase Storage charges egress; R2 does not. Simple swap: update upload/download URLs. No vendor lock β standard S3 API | Firebase Storage bill > β¬30/mo | M (3d) | 8 |
| #255 | Redis/Valkey caching layer β Add Redis (Valkey open source) on Oracle server for: leaderboard cache (1hr TTL), nearby riders cache (30s), feed cache (5min). Reduces Firestore reads by ~70% for social features. Free on Oracle (4 OCPUs, 24GB RAM has headroom) | 5,000 daily active users | M (3d) | 9 |
| #256 | Oracle β Hetzner migration (if Oracle free tier disappears) β All Oracle services containerised (Docker Compose). Migration = copy docker-compose.yml + volumes to Hetzner CX21 (β¬5/mo, Frankfurt = EU). Services: Discord bot, support daemon, routing server (OSRM). Preparation: document all volumes, keep compose file up to date | If Oracle reclaims free tier | S (1d prep) | 10 |
| #257 | Phase 4: Full backend extraction (50k+ users) β Replace Firebase as primary backend with: FastAPI (Python) on Cloud Run (europe-west4, scale to zero), Supabase for PostgreSQL + Auth (can keep Firebase Auth as identity provider, just switch DB). Firestore stays for real-time feeds only. Eliminates vendor lock risk entirely | 50,000 registered users OR Google announces Firebase pricing change | XL (4β6w) | 8 |
| #258 | Anti-lock preparation (ongoing) β Abstract all Firebase calls behind service classes (already partially done). Document data export procedures. Maintain Firestore export to GCS weekly (backlog #backup). Never use Firebase-specific features that have no open standard equivalent | Now β ongoing | S (1d) | 10 |
| #259 | CDN + DDoS protection β Cloudflare (free plan) in front of equitrail.horse + support.equitrail.horse. Protects Plesk, hides origin IP, free SSL, caching static assets. 5-minute setup | Now | XS (2h) | 8 |
| #260 | Load testing baseline β locust script simulating 1k concurrent users: ride save, feed load, leaderboard, nearby riders. Run before each major release. Document baseline metrics |
Before Play Store public launch | M (2d) | 7 |
Vendor lock risk matrixΒΆ
| Vendor | Lock risk | Mitigation | Escape hatch |
|---|---|---|---|
| Firebase/Google | Medium | Abstract behind service classes, export weekly | Supabase, Neon, Appwrite |
| Oracle free tier | Low-Medium | Docker Compose, portable | Hetzner (β¬5/mo), DigitalOcean |
| Play Store | None (Android monopoly) | β | Sideload APK as backup |
| App Store | None (iOS monopoly) | β | β |
| Office 365 | Low | Standard SMTP | Brevo, SES, Postfix |
| Plesk hosting | Low | Static files, easy copy | Cloudflare Pages, Hetzner |
π Growth Campaign Plan β 12-Month RoadmapΒΆ
Target market: Dutch recreational horse riders (primary), Belgium + Germany (month 6+). Equestrian sport in NL: ~400,000 registered riders, ~1.5M horse enthusiasts. Word-of-mouth at the stable is the #1 growth channel β design for it.
Realistic projectionsΒΆ
| Milestone | Timeline | Trigger |
|---|---|---|
| 100 users | Month 1 | Beta testers + referrals |
| 500 users | Month 2β3 | App Store live + first influencer |
| 2,000 users | Month 4β6 | Paid ads + manege partnerships |
| 5,000 users | Month 6β9 | Viral route sharing, newsletter |
| 10,000 users | Month 10β12 | Expansion BE/DE, press |
| 25,000 users | Year 2 | Scale paid + community flywheel |
Backlog itemsΒΆ
| # | Item | Timeline | Budget | Est. | Win |
|---|---|---|---|---|---|
| #261 | App Store & Play Store ASO β Professional screenshots (phone + tablet), keyword-optimised NL/EN/DE/FR descriptions, short promo video (foreground GPS permission), A/B test icons. ASO = highest ROI growth lever. | Month 1 | β¬0 | M (3d) | 10 |
| #262 | Review request flow β In-app prompt after 3rd completed ride (not annoying): "Vind je EquiTrail fijn? Help ons groeien π΄" β direct to Play Store / App Store. Also in newsletter footer and after resolved support ticket (2 days later). | Month 1 | β¬0 | S (1d) | 10 |
| #263 | Referral campaign push β Active marketing of existing ET-code system. "Nodig 3 vrienden uit, allen 1 maand PRO gratis". WhatsApp template, Instagram story template, stable poster (A4 PDF) for download at equitrail.horse/deel. | Month 1 | β¬0β100 design | S (1d) | 9 |
| #264 | Instagram account (@equitrail.horse) β 3x/week posting: GPS track animations (auto-generated from community_trails), rider spotlights, tips, "Rit van de week". Dutch primary, English secondary. Content calendar 4 weeks ahead. Target: 1k followers month 3. | Month 1 ongoing | β¬0 | M (content ongoing) | 8 |
| #265 | Micro-influencer outreach (NL) β Identify 10 Dutch equestrian Instagram accounts 5kβ50k followers (lifestyle focus, not only competition). Offer: 6 months PRO free + branded content brief. No cash initially. Follow-up with paid deal if conversion good. Target accounts: managebloggers, jonge ruiters, KWPN fokkers, dressuur-lifestylers | Month 2 | β¬0 (PRO codes) | M (2d outreach + follow-up) | 9 |
| #266 | Manege/rijschool partnership programme β Email 50 managements in NL: offer "Manege PRO deal" β school gets 5 free PRO accounts, students get 30-day free trial on sign-up with stable code. Tracking: stableCode field in Firestore. Partner logo on website "Aangesloten managements" |
Month 2β3 | β¬0 | M (2d) | 8 |
| #267 | Google UAC (Universal App Campaigns) β Android-only first. β¬200/month initial budget, target: equestrian keywords + competitor terms. Target CPI (cost per install) < β¬1.50. Measure retention D7/D30 to optimise. Pause if CPI > β¬3 without improving. | Month 3 | β¬200/mo | S (setup 1d) | 8 |
| #268 | Facebook/Instagram Ads β Target: NL women 20β45, interests: paarden, manege, KWPN, dressuur, springen. Lookalike from existing users. β¬150/month initial. Creative: GPS track animation video, "Houd jij je ritten bij?" | Month 3 | β¬150/mo | S (setup 1d) | 7 |
| #269 | TikTok / Reels content β Short GPS track animations (30s), "dag in het leven van een ruiter" format. Auto-generate from community_trails data (backlog #72). If Instagram Reels performing: repurpose to TikTok. Target: younger riders 16β28 | Month 4 | β¬0 | M (2d setup) | 7 |
| #270 | Press & media β Reach out to: Hoefslag.nl, Paardenkrant, Ruitersport.com, Horses.nl. Press kit: app demo video, stats, unique angle ("GPS rit app speciaal voor ruiters, gemaakt door een ruiter"). Target: 1 feature article month 4 | Month 4 | β¬0 | M (2d) | 9 |
| #271 | Community challenges β Monthly challenge: "Meeste km in april" (leaderboard), "Langste rit van de week", seasonal (zomer/winter). Share results to feed + social. Creates recurring engagement and shareability | Month 3 ongoing | β¬0 | M (2d) | 8 |
| #272 | Belgium expansion β French/Dutch-speaking Belgium. Translate Store listing to FR (done) + NL. Reach out to Belgian equestrian federation. Target Belgian equestrian Instagram accounts. Budget: same as NL phase, 3 months later | Month 6 | β¬100/mo extra ads | S (1d) | 7 |
| #273 | Germany expansion β DE translation done. Target: DOKR (Deutsche Olympiade-Komitee fΓΌr Reiterei) community, German equestrian Instagram. German App Store listing. | Month 7 | β¬200/mo extra ads | S (1d) | 7 |
| #274 | Partnerships with horse event organisers β Sponsor presence at KWPN Keuring, Dutch Championships, local concours. EquiTrail booth/banner + QR code to download. Leaflets at check-in. Budget: β¬200β500 per event | Month 5+ | β¬300/event | S (1d prep) | 8 |
| #275 | Ambassador programme β 5β10 active power-users get "EquiTrail Ambassador" role (Discord + app badge). Perks: lifetime PRO, exclusive features preview, monthly video call. Obligation: share 2x/month, gather stable feedback | Month 3 | β¬0 | S (1d) | 8 |
Budget planΒΆ
| Period | Monthly budget | Allocation |
|---|---|---|
| Month 1β2 | β¬0β100 | Design assets only |
| Month 3β4 | β¬400/mo | UAC β¬200 + FB/IG β¬150 + tools β¬50 |
| Month 5β6 | β¬700/mo | UAC β¬300 + FB/IG β¬250 + events β¬150 |
| Month 7β12 | β¬1,200/mo | Scale winning channels + BE/DE ads |
| Year 2 | β¬2,500/mo | Full funnel if revenue supports (target: CAC < LTV/3) |
Key metrics to track (monthly)ΒΆ
- Downloads (organic vs paid)
- D1 / D7 / D30 retention
- Rides created per user per week
- Referrals activated
- Review score (Play Store / App Store)
- CAC (cost per acquired user) by channel
- MRR growth
π¨ Growth & Infrastructure Threshold AlertingΒΆ
Goal: Be ahead of scaling issues, not reactive. Get alerted BEFORE hitting limits, not when the app is already slow or expensive. Every alert should fire with enough lead time (2β4 weeks) to act without panic.
| # | Item | Trigger | Est. | Win |
|---|---|---|---|---|
| #276 | Firebase spend alerting β GCP billing alerts: β¬20/mo (info), β¬50/mo (warning), β¬100/mo (urgent β scale review meeting). Firebase quota alerts: Firestore reads >80% daily limit, Storage >80% free tier. Alert via: Discord #ops-alerts + email nossiej@gmail.com | Now | XS (2h) | 10 |
| #277 | User growth threshold dashboard β Automated weekly Discord message (Monday 09:00) via cron on Oracle: "π EquiTrail week report: {users_total} users Β· {new_this_week} new Β· {rides_this_week} rides Β· {dau} DAU Β· Firebase cost: β¬{cost}". Pulls from Firestore Admin SDK + GCP billing API | Month 1 | S (1d) | 9 |
| #278 | Firestore performance monitoring β Track read/write counts daily. Alert when: daily reads >30k (Spark limit: 50k), daily writes >15k (limit: 20k), Storage >3GB (limit: 5GB). Cron script checks Firestore usage stats via GCP API β posts to Discord if thresholds hit | Now | S (1d) | 9 |
| #279 | Scaling trigger checklist β Auto-generated checklist posted to Discord when threshold reached: "β οΈ Firestore approaching free tier limit. Actions needed: 1) Enable Blaze billing 2) Add spend cap 3) Review top write operations 4) Enable TTL on active_riders". Prevents scrambling at the last minute. | Automatic | S (0.5d) | 9 |
| #280 | Oracle server health alerts β Daily check: CPU >80% avg, RAM >85%, disk >80%, bot uptime, support daemon uptime, routing server uptime. Alert via Discord #ops-alerts. Script: extend existing scripts/dashboard.py with thresholds |
Now | S (0.5d) | 8 |
| #281 | App crash rate alerting β Firebase Crashlytics (add to app): alert if crash-free session rate drops below 99.5%. Daily digest of top crashes. Integrates with existing Discord bot β #bug-reports | Month 1 | S (1d) | 9 |
| #282 | Monthly scaling review (calendar) β Recurring calendar item: 1st Monday of every month, 30 minutes. Checklist: review Firebase costs vs budget, user growth vs projections, infrastructure load, upcoming thresholds. Documented decision: scale up / hold / optimise. | Now | XS (30min setup) | 10 |
| #283 | GCP budget anomaly detection β Enable GCP "Budget alerts with forecast" β warns if spending trajectory will exceed budget before end of month. Also: set hard cap on Firebase Functions (β¬0 until intentionally enabled) to prevent runaway costs | Now | XS (1h GCP console) | 9 |
| #284 | Play Store / App Store review monitoring β Daily check of new reviews (Play Store API + App Store RSS). Negative review (1β2 stars) β Discord alert within 1h β admin can respond fast. Pattern: 3+ similar negative reviews in a week β create auto-backlog bug item | Month 1 | S (1d) | 8 |
| #285 | Infrastructure scaling playbook β docs/scaling_playbook.md: step-by-step for each threshold. "When Firebase reads hit 40k/day: [step 1] add Firestore TTL on active_riders [step 2] enable caching [step 3] ...". Written once, followed under pressure. |
Month 1 | S (1d) | 8 |
Alert routingΒΆ
| Alert type | Channel | Response time |
|---|---|---|
| Firebase cost > β¬50 | Discord #ops-alerts + email | 24h |
| Firebase quota > 80% | Discord #ops-alerts | 48h |
| App crash rate < 99.5% | Discord #bug-reports | 4h |
| Oracle disk > 80% | Discord #ops-alerts | 24h |
| Oracle service down | Discord #ops-alerts | 1h |
| Negative review spike | Discord #ops-alerts | 1h |
| User growth milestone (100/500/1k/5k/10k) | Discord #general π | Celebrate! |