What it does
Forfyt is a habit-accountability app. You pledge a fixed amount on a habit, prove every check-in with a photo that's automatically AI-verified — not a tap of a checkbox — and if you miss one and don't catch up within 48 hours, you donate the pledged amount yourself, directly, to a charity you chose. Forfyt never holds the money and takes 0% of any donation.
Inspiration
Every habit tracker I'd used had the same flaw: tapping "done" costs nothing, so streaks get faked and the app gets abandoned within a week. I wanted something where the accountability was real — where skipping a habit had an actual, felt consequence, but one that did good in the world rather than just enriching an app developer.
How I built it
- iOS: SwiftUI, MVVM, RevenueCat for subscriptions, AVFoundation for live camera check-ins, ASWebAuthenticationSession for the Every.org donation handoff
- Backend: Node.js, Express, Drizzle ORM, PostgreSQL on Supabase, deployed on Railway
- Vision: OpenRouter routing to a vision-capable model, checking that a submitted photo actually matches the claimed habit
- Payments: RevenueCat + StoreKit for the Pro subscription; Every.org donate links for the charity side — two entirely separate money flows, deliberately, so Forfyt is never a party to a donation
Challenges I ran into
- The donation flow had to work without a partner account. Every.org's
webhook confirmation requires partner approval, which wasn't going to land
in time. I built the flow around the
success_urlredirect instead, with a manual "I've already donated" fallback — client-asserted, but there's no money in Forfyt's custody, so the only thing at stake if someone lies to it is the accountability they signed up for. - A subtle timezone bug in the backend computed "today" in the server's UTC zone instead of the user's, so anyone east of UTC saw their habits appear a day late. Found it by testing on a real device on a different network than my dev machine — the kind of bug that never shows up on a simulator.
- Two App Store rejections, including a first-submission review flag and a missed EULA link in the app description. Both were metadata gaps, not product problems, but they cost real days against the deadline.
- A locked test Apple ID mid-submission forced rebuilding my entire seeded demo account from scratch, twice, on a different account, to keep the review moving.
What I learned
That the hardest bugs are rarely in the feature you're proud of — they're in the seams between systems (timezone handling, payment provider integration, App Store metadata) that only show up under real conditions.
Built With
- every.org
- express.js
- node.js
- openrouter
- postgresql
- railway
- revenuecat
- signinwithapple
- storekit
- supabase
- swift
- swiftui
- typescript
Log in or sign up for Devpost to join the conversation.