Project
Sociko
Member, membership and revenue management SaaS for gyms, studios and clubs in Mexico. The differentiator is the collections list: every lapsed member is flagged with their phone number next to them — recovering a single one pays for the subscription. The gym's money never flows through the platform.
Pre-launch — live in production Own product — in development Founder & Engineer (Full Stack — Product, Backend, Infrastructure) Public summary
Own product in pre-launch, already live in production and operated solo. Multi-tenant SaaS handling gym members' data on behalf of each gym; implementation details are summarized at a high level.
Stack
Angular 21TypeScriptTailwind CSS 4Firebase HostingFirestoreFirebase AuthCloud FunctionsStripe ConnectResendPWAGitHub Actions
Impact
- Front-desk check-in answers on the spot whether a member is current — and every lapsed member who walks in gets flagged on the collections list with their phone number, which is where the gym recovers unpaid monthly fees.
- Annual plan with two months free, with the member receipt and the renewal notice sent by email — the gym stops chasing renewals by memory.
- Membership status is always derived from the expiry date, never stored: no cron job flipping flags, no data lying at midnight.
- Optional online billing via Stripe Connect direct charges: payments land in the gym's own Stripe account under the gym's name — the platform never touches the funds.
- Offline-first PWA: the member roster stays readable at the front desk even when the internet drops.
What I did
- Fully civil date model (YYYY-MM-DD strings) with a lint rule banning `new Date()` outside a single helper — in an expirations business, one timezone slip turns away a paying member at the door.
- Monthly renewals anchored to the original date with end-of-month clamping, verified by mutation testing: 12 on-time renewals add up to exactly one calendar year.
- Atomic renew-and-charge transactions keyed by idempotency: a double tap on 'Renew' cannot duplicate the income record or the membership.
- Full technical SEO: public routes prerendered to real HTML at build time, per-page metas, JSON-LD and sitemap.
- The collections list hands over a WhatsApp message already written for each lapsed member, so recovering one is a tap instead of a task.
- A daily sweep enforces the 90-day clause in the Terms: it warns twice before closing an inactive account, so the promise in the legal text is code and not a paragraph.
Architecture
- Angular 21 (signals, standalone components) as a PWA on Firebase Hosting; Cloud Functions v2 (Node 22) as the backend; multi-tenant Firestore with every document under organizations/{orgId}.
- Stripe webhooks are the single source of truth for plans and feature flags; optional member billing uses Connect direct charges with an application fee.
- CI gates (lint + tests on both layers) with automatic deploy to Firebase on every commit to main.
Tags
SaaSMulti-tenantFitnessStripeFirebasePWALATAMFull Stack
