← Back to projects

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