ForgeFit is an installable fitness, nutrition, grocery, and equipment PWA. It combines a guided exercise catalog, a weekly workout planner, goal-based macro estimates, recipes filtered by diet preference (vegan, vegetarian, eggetarian, non-vegetarian), a consolidated grocery list, and links to real retailers for groceries, dishes, and equipment.
- Next.js 16.2.11, React 19, TypeScript, Tailwind CSS 4
- Turborepo with pnpm workspaces
- Supabase Auth, PostgreSQL, Row Level Security, migrations, and pgTAP
- Vitest, Testing Library, and Playwright
apps/web Next.js App Router PWA
packages/domain Validation, nutrition, grocery, and commerce rules
packages/ui Shared accessible UI primitives
packages/supabase Database-facing types and client utilities
packages/config Shared TypeScript configuration
supabase/migrations Schema, triggers, RPC, and RLS policies
supabase/seed.sql 12 recipes (the 63-exercise library lives in a migration)
supabase/tests pgTAP database tests
- Node.js 22 or newer
- pnpm 10.15.1 (
corepack enableis recommended) - A Supabase project
- Optional: Docker Desktop and the Supabase CLI for a fully local database
This repository never needs a Supabase service-role key in the web application.
-
Install dependencies:
pnpm install
If pnpm is not installed globally:
npx --yes pnpm@10.15.1 install
-
Copy the environment template:
cp .env.example apps/web/.env.local
On PowerShell:
Copy-Item .env.example apps/web/.env.local
-
Set
NEXT_PUBLIC_SUPABASE_URL,NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, andNEXT_PUBLIC_SITE_URL. Use the publishable/anon client key—not the service-role key. -
Apply the database schema and seed.
Local Supabase:
supabase start supabase db reset
Managed development project:
supabase login supabase link --project-ref YOUR_PROJECT_REF supabase db push --include-seed
Keep email confirmation disabled for a local demo or configure the project’s confirmation template to redirect to
/auth/confirm. Enable confirmation for a deployed environment. -
Start the application:
pnpm dev
Open http://localhost:3000. Registration creates a profile and one default workout plan. Finish onboarding before entering authenticated routes.
pnpm dev # run the Next.js development server
pnpm build # production build through Turborepo
pnpm lint # ESLint, zero warnings allowed
pnpm typecheck # strict TypeScript check
pnpm test # domain and component tests
pnpm format:check # verify Prettier formatting
pnpm test:e2e # Playwright phone, tablet, and desktop projects
supabase test db # pgTAP schema and seed assertions; local Supabase requiredAuthenticated Playwright coverage expects a completed test account:
FORGEFIT_E2E_EMAIL=test@example.com FORGEFIT_E2E_PASSWORD='your-password' pnpm test:e2e- Supabase SSR uses PKCE and cookie-backed sessions.
proxy.tsrefreshes expired sessions. - Every exposed table has RLS enabled. Catalog rows are readable by authenticated users; profile, workout, grocery, completion, and owned-equipment rows are restricted to
auth.uid(). - The browser only receives the publishable key. User identity is revalidated in every Server Action.
- Grocery insertion is an authenticated PostgreSQL RPC using an atomic
ON CONFLICTquantity increment. - The service worker caches only icons and the offline page. It never caches authenticated HTML or Supabase data.
ForgeFit uses Mifflin–St Jeor BMR, standard activity multipliers, and goal adjustments of +300 kcal for muscle gain, -400 for fat loss, 0 for maintenance, and -200 for recomposition. Targets never fall below estimated BMR. Protein varies by goal, fat is 0.8 g/kg, and carbohydrates receive remaining calories.
These values are educational estimates, not medical advice. The MVP is limited to adults aged 18 or older.
ForgeFit doesn't sell anything, show prices, or take orders. Where a plan leads to a purchase, it links to the retailer's own search page and the retailer handles the rest:
- Groceries (Nutrition → Grocery): each item links to a search on BigBasket, Blinkit, Zepto, Swiggy Instamart, or JioMart. The chosen store is saved on the profile.
- Dishes (recipe pages): "Order this dish" searches Swiggy or Zomato.
- Equipment (Train → Equipment): items you don't own link to Amazon, Flipkart, and Decathlon. Marking what you own lets plans use it.
Retailers are listed in packages/domain/src/commerce.ts; adding one is a name and a search-URL builder. No API keys are needed.
ForgeFit is designed to run on free tiers until it has a few hundred regular users. The free plan has four catches, handled as follows.
Project pausing. Free projects with too little database activity for 7 days are paused (a warning email arrives first). Restore it from the Supabase dashboard; it takes a few minutes and keeps all data. For day-to-day development, prefer a local database (supabase start, which needs Docker Desktop) so the cloud project is only used by the deployed app.
Database size. Above 500 MB the database becomes read-only and workouts can't be saved. The weekly backup workflow also reports the size and fails, which triggers a GitHub email, once it passes 350 MB. That is the signal to move to Supabase Pro.
Email. Supabase's built-in email only delivers to members of the project's team, at 2 messages an hour, so real users never receive confirmation or password-reset emails. ForgeFit sends through Resend instead (free plan: 3,000 emails a month, 100 a day). Resend requires a domain you own.
-
Resend: create an account, add your domain under Domains, and add the DNS records it shows at your domain registrar. Wait until the domain shows as verified. Then create an API key with "Sending access".
-
Supabase → Authentication → Emails → SMTP Settings: enable custom SMTP and enter:
Field Value Sender email no-reply@<your-domain>Sender name ForgeFitHost smtp.resend.comPort 465Username resendPassword your Resend API key -
Supabase → Authentication → Emails → Templates: paste
supabase/templates/confirmation.htmlinto "Confirm signup" (subject: Confirm your ForgeFit email) andsupabase/templates/recovery.htmlinto "Reset password" (subject: Reset your ForgeFit password). Both link to/auth/confirm, which signs the person in from the link. -
Supabase → Authentication → URL Configuration: set Site URL to the app's address (
http://localhost:3000until it is deployed) and addhttp://localhost:3000/**plus the production URL with/**to Redirect URLs. -
Supabase → Authentication → Sign In / Providers → Email: keep "Confirm email" on.
For development, point Supabase's SMTP at Ethereal, a free fake mail server. Nothing is delivered: every confirmation and reset email, for any address, lands in one web inbox. No domain or sign-up needed, so you can test sign-up and password reset as often as you like.
- Create an inbox at ethereal.email ("Create Ethereal Account") and keep the username and password.
- Supabase → Authentication → Emails → SMTP Settings: sender email = the Ethereal username, sender name
ForgeFit, hostsmtp.ethereal.email, port587, username and password from step 1. - Supabase → Authentication → Rate Limits: raise "emails sent per hour" (for example to 100) so repeated tests aren't blocked.
- Do steps 3–5 of the Resend setup above (templates, URL configuration, "Confirm email" on).
- Test: sign up in the app with any new address on the
ethereal.emaildomain (lifter1@ethereal.email,lifter2@ethereal.email, …). Open ethereal.email/messages (log in with the Ethereal credentials) and click the link in the email.
Supabase allows one sign-up or reset email per address per 60 seconds, so use a fresh address each time. Ethereal keeps messages for about 15 days. Switch the SMTP settings to Resend before real people use the app.
The free plan has no automatic backups. .github/workflows/database-backup.yml runs every Monday at 02:00 IST (and on demand from the Actions tab). It dumps roles, schema and data, encrypts them, and keeps each backup as a workflow artifact for 30 days.
Add two repository secrets under Settings → Secrets and variables → Actions:
SUPABASE_DB_URL: the Session pooler connection string from Supabase → Connect. The directdb.<ref>.supabase.cohost is IPv6-only and GitHub runners can't reach it.BACKUP_PASSPHRASE: a long random passphrase. Keep a copy in your password manager; without it the backups can't be opened. Encryption matters because this repository is public, so its workflow artifacts can be downloaded by other GitHub users.
To restore, download the artifact, then:
gpg --decrypt forgefit-db.tar.gz.gpg | tar xz
psql "$TARGET_DB_URL" --single-transaction -f roles.sql -f schema.sql \
-c "SET session_replication_role = replica" -f data.sqlThe production build provides a web manifest, maskable icons, install guidance, security headers, a minimal offline fallback, and responsive navigation at phone, tablet, and desktop widths. Serve the deployed application over HTTPS for installation. Configure the production URL in both NEXT_PUBLIC_SITE_URL and Supabase Auth redirect settings.
Native App Store and Play Store binaries are outside this MVP. A future Expo application can reuse packages/domain, packages/ui design tokens, and the Supabase contracts.