Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
128 commits
Select commit Hold shift + click to select a range
1b496b5
first changes
AlexandruIordache-MRM Nov 28, 2025
6764a2c
before updating to latest capacitor
AlexandruIordache-MRM Nov 29, 2025
37cc027
Capacitor updated and Capacitor Preferences installed
AlexandruIordache-MRM Nov 29, 2025
bc10853
Merge pull request #1 from alex-iordache/capacitor-update
alex-iordache Nov 29, 2025
75f9f69
commit before clerk
AlexandruIordache-MRM Dec 27, 2025
7a1853b
Clerk+Vercel integration
AlexandruIordache-MRM Dec 29, 2025
722b365
Add client-side redirect logic for authenticated users
AlexandruIordache-MRM Dec 29, 2025
dbd9574
Fix routing: use window.location for Ionic router compatibility
AlexandruIordache-MRM Dec 29, 2025
94b8ed7
Fix white page: use window.location for sign-in redirect
AlexandruIordache-MRM Dec 29, 2025
371bacc
Implement email verification for verified domains
AlexandruIordache-MRM Dec 29, 2025
4bf973f
Fix sign-in page vertical centering and safe area support
AlexandruIordache-MRM Dec 29, 2025
c9bd4bc
Remove forceRedirectUrl to prevent browser opening after sign-in
AlexandruIordache-MRM Dec 29, 2025
703ff6f
Disable server-side auth protection to prevent browser opening
AlexandruIordache-MRM Dec 29, 2025
b3bdb73
Add aggressive external browser blocking for Capacitor
AlexandruIordache-MRM Dec 29, 2025
c64bb9b
Fix hydration error and prepare for Vercel env vars
AlexandruIordache-MRM Dec 29, 2025
a9752b0
Add allowedRedirectOrigins for Capacitor - official Clerk solution
AlexandruIordache-MRM Dec 29, 2025
36dcec2
Add Sign In/Sign Out buttons to Settings page with home redirect
AlexandruIordache-MRM Dec 30, 2025
da0d4dc
Enable guest access - remove forced authentication from app routes
AlexandruIordache-MRM Dec 30, 2025
82215a8
Fix sign-out: use signOutCallback for proper redirect timing
AlexandruIordache-MRM Dec 30, 2025
9fdd740
Fix sign-out using useClerk hook per Clerk documentation
AlexandruIordache-MRM Dec 30, 2025
b970562
Implement Phase 2: Access control with organization and subscription …
AlexandruIordache-MRM Dec 30, 2025
8a4c9ca
Fix: Escape apostrophe in PaywallModal
AlexandruIordache-MRM Dec 30, 2025
ce852e8
Phase 2: Add Clerk Billing with PricingTable and subscription management
AlexandruIordache-MRM Dec 30, 2025
40041c8
Update sign-up flow to redirect to /subscribe for non-org users
AlexandruIordache-MRM Dec 30, 2025
c6216be
Fix PaywallModal to redirect to /sign-up instead of /sign-in
AlexandruIordache-MRM Dec 30, 2025
5b99bf0
Fix OAuth redirect to use /post-signup-redirect for all sign-up flows
AlexandruIordache-MRM Dec 30, 2025
0a9cc7a
Add env variables documentation and local .env.local
AlexandruIordache-MRM Dec 30, 2025
5e32c19
Fix: Read Clerk OAuth redirect query parameters on sign-in page
AlexandruIordache-MRM Dec 30, 2025
b8665ec
Fix: Use window.location.search for query params in sign-in redirect
AlexandruIordache-MRM Dec 30, 2025
7b26865
Add redirect URL props to ClerkProvider for mobile compatibility
AlexandruIordache-MRM Dec 30, 2025
fdb3e8b
Add detailed console logging to debug mobile OAuth redirect
AlexandruIordache-MRM Dec 30, 2025
8601bf2
Simplify: Use window.location for external Stripe redirect
AlexandruIordache-MRM Dec 30, 2025
d695b82
Create separate web and mobile subscribe pages for external payment
AlexandruIordache-MRM Dec 30, 2025
0d0a7f8
Fix apostrophe escaping in subscribe page
AlexandruIordache-MRM Dec 30, 2025
05128e3
Clean mobile payment solution using Browser.open()
AlexandruIordache-MRM Dec 30, 2025
a24ecac
Beautiful welcome page with inline pricing and external payment
AlexandruIordache-MRM Dec 30, 2025
d75bcce
Fetch real pricing from Clerk API for welcome page
AlexandruIordache-MRM Dec 30, 2025
8554837
Use Clerk PricingTable directly with Clerk billing
AlexandruIordache-MRM Dec 30, 2025
22de0f7
Implement web-only registration and payment flow for Google Play comp…
AlexandruIordache-MRM Dec 30, 2025
dac0b1e
Mobile-optimized web pages for sign-up and subscription
AlexandruIordache-MRM Dec 30, 2025
22fdb73
Fix duplicate minHeight style property
AlexandruIordache-MRM Dec 30, 2025
5e2d552
Open sign-up and subscription in system browser not in-app browser
AlexandruIordache-MRM Dec 30, 2025
9bb3791
Use Browser.open with presentationStyle fullscreen
AlexandruIordache-MRM Dec 30, 2025
9b59e15
Simplify external links to use target=_blank
AlexandruIordache-MRM Dec 30, 2025
0f0b788
Use App.openUrl() to properly open URLs in system browser
AlexandruIordache-MRM Dec 30, 2025
6a4c4df
Fix App.openUrl dynamic import for Next.js compatibility
AlexandruIordache-MRM Dec 30, 2025
77f0c60
Fix App.openUrl dynamic import for Next.js compatibility
AlexandruIordache-MRM Dec 30, 2025
b8ec28a
Restore Clerk organizations with domain fallback
AlexandruIordache-MRM Dec 30, 2025
e9e6a08
Revert "Restore Clerk organizations with domain fallback"
AlexandruIordache-MRM Dec 30, 2025
1300d44
Revert "Fix App.openUrl dynamic import for Next.js compatibility"
AlexandruIordache-MRM Dec 30, 2025
f3245e8
Revert "Fix App.openUrl dynamic import for Next.js compatibility"
AlexandruIordache-MRM Dec 30, 2025
f3e0fe6
Revert "Use App.openUrl() to properly open URLs in system browser"
AlexandruIordache-MRM Dec 30, 2025
b977ab3
Guard organization check using auth orgId and remove useOrganization …
AlexandruIordache-MRM Dec 30, 2025
82ba2e6
Use AppLauncher to open sign-up/subscribe in system browser
AlexandruIordache-MRM Dec 30, 2025
8a91085
Use Clerk sign-in only; fix sign-up link and system-browser subscribe
AlexandruIordache-MRM Dec 30, 2025
6c088ed
Remove browser blocker to allow external sign-up links
AlexandruIordache-MRM Dec 30, 2025
6339262
Fix sign-up flow to external browser; redirect to subscribe
AlexandruIordache-MRM Dec 30, 2025
5c311a2
Fix subscribe-web blank state with ClerkLoaded/Loading
AlexandruIordache-MRM Dec 30, 2025
0c848c4
Enforce authentication and in-app sign-up flow
AlexandruIordache-MRM Dec 30, 2025
d29c977
Fix subscription and sign-up flow issues
AlexandruIordache-MRM Dec 30, 2025
93b1c29
Fix: Resolve three Clerk authentication issues
AlexandruIordache-MRM Dec 30, 2025
148ad43
Fix: Remove CSS password hiding - let Clerk Dashboard settings contro…
AlexandruIordache-MRM Dec 30, 2025
8f65da3
Add debug box to sign-up page for mobile vs browser diagnostics
AlexandruIordache-MRM Dec 30, 2025
cd9170c
Add Clerk publishable key detection to debug box for mobile vs browse…
AlexandruIordache-MRM Dec 30, 2025
9a5b472
Add Clerk publishable key detection to debug box for mobile vs browse…
AlexandruIordache-MRM Dec 30, 2025
75dbcfe
Improve Clerk publishable key detection from multiple sources
AlexandruIordache-MRM Dec 30, 2025
53af47e
Fix build error and add .clerk to gitignore to prevent wrong key commits
AlexandruIordache-MRM Dec 30, 2025
b4dcad2
Remove unused SignUpWebPage component - only SignUpPage is used
AlexandruIordache-MRM Jan 1, 2026
88999b6
Fix sign-in component centering with explicit flexbox styles
AlexandruIordache-MRM Jan 1, 2026
018dcf9
Putting back the sign-up fields
AlexandruIordache-MRM Jan 1, 2026
5a5f293
Add hard reload button to sign-up debug box
AlexandruIordache-MRM Jan 1, 2026
6116339
Improve sign-up debug logging and remove deprecated afterSignInUrl
AlexandruIordache-MRM Jan 1, 2026
9ac9e99
Make sign-up debug box mobile-friendly (stack buttons, constrain width)
AlexandruIordache-MRM Jan 1, 2026
fcdbfa1
Make sign-up debug box mobile-friendly (stack buttons, constrain width)
AlexandruIordache-MRM Jan 1, 2026
82a8ee3
Android: remove WebView UA token so Clerk matches browser SignUp UI
AlexandruIordache-MRM Jan 1, 2026
453f09a
Android: enable third-party cookies for Clerk auth in WebView
AlexandruIordache-MRM Jan 1, 2026
ff64999
Move debug box below auth forms and fix mobile width/button layout
AlexandruIordache-MRM Jan 1, 2026
dace87c
Native: open /sign-up in system browser to avoid WebView password field
AlexandruIordache-MRM Jan 1, 2026
582f9b7
Use in-app browser tab for sign-up and close it via deep link
AlexandruIordache-MRM Jan 1, 2026
0566cca
Native sign-up: open in-app tab immediately and keep WebView on sign-in
AlexandruIordache-MRM Jan 1, 2026
54f5602
Auto sign-in after native signup using Clerk sign-in token and deep link
AlexandruIordache-MRM Jan 1, 2026
2a35e4a
Revert: undo Jan 1, 2026 changes
AlexandruIordache-MRM Jan 1, 2026
e847570
Enable Android WebView remote debugging in debug builds
AlexandruIordache-MRM Jan 1, 2026
f16b767
Disable CapacitorHttp so Clerk uses WebView fetch/cookies
AlexandruIordache-MRM Jan 1, 2026
3de3bb3
Fix: disable CapacitorHttp so Clerk uses WebView fetch/cookies
AlexandruIordache-MRM Jan 1, 2026
650cce4
Fix hydration mismatch on sign-up debug fields
AlexandruIordache-MRM Jan 2, 2026
a3c6d60
Chore: avoid SSR class mismatch on IonButton
AlexandruIordache-MRM Jan 2, 2026
ad8a2ab
Refactor: extract debug box into reusable component
AlexandruIordache-MRM Jan 2, 2026
fae6d98
Chore: remove unused legacy pages/components
AlexandruIordache-MRM Jan 2, 2026
02a344d
Docs: consolidate all project notes into README
AlexandruIordache-MRM Jan 2, 2026
d19991b
Chore: update native app icons and splash screens
AlexandruIordache-MRM Jan 2, 2026
cd5daaa
Chore: add more padding to Android launcher icons
AlexandruIordache-MRM Jan 2, 2026
881d52e
UI: center Stress Break card on home
AlexandruIordache-MRM Jan 2, 2026
86a25cb
UI: update paywall modal copy and styling
AlexandruIordache-MRM Jan 2, 2026
e6c360a
Test: use Clerk CheckoutButton for Pro plan
AlexandruIordache-MRM Jan 2, 2026
3b63fd0
Fix: TS moduleResolution for Clerk experimental imports
AlexandruIordache-MRM Jan 2, 2026
4412878
UX: add in-app subscribe screen and auto-open checkout in browser
AlexandruIordache-MRM Jan 2, 2026
86b250f
UX: in-app subscribe plan box + minimal browser checkout
AlexandruIordache-MRM Jan 2, 2026
a1eb98e
Fix: register /subscribe route in AppShell
AlexandruIordache-MRM Jan 2, 2026
ca6bd18
Fix: allow /subscribe route (wrap AppShell routes in Switch)
AlexandruIordache-MRM Jan 2, 2026
dc06530
Fix: remove AppShell catch-all redirect so /subscribe works
AlexandruIordache-MRM Jan 2, 2026
ea96925
UX: redirect locked practices to /subscribe
AlexandruIordache-MRM Jan 2, 2026
a3085ca
UI: improve subscribe plan box title and currency display
AlexandruIordache-MRM Jan 2, 2026
d89ddbc
Fix: use embedded Clerk checkout in minimal subscribe-web
AlexandruIordache-MRM Jan 2, 2026
addf645
Fix: restore Clerk checkout drawer and fix mobile scaling on subscrib…
AlexandruIordache-MRM Jan 2, 2026
574b6c3
UI: constrain and center Clerk checkout drawer on subscribe-web
AlexandruIordache-MRM Jan 2, 2026
d35d776
Fix: show visible fallback CTA on minimal subscribe-web
AlexandruIordache-MRM Jan 2, 2026
f045ca9
Revert "Fix: show visible fallback CTA on minimal subscribe-web"
AlexandruIordache-MRM Jan 2, 2026
b7d6ce7
Revert "UI: constrain and center Clerk checkout drawer on subscribe-web"
AlexandruIordache-MRM Jan 2, 2026
8dc5d73
Fix: use Clerk checkoutProps appearance to size checkout drawer
AlexandruIordache-MRM Jan 2, 2026
8381e0f
Fix: style Clerk checkout drawer using stable cl-* classes (subscribe…
AlexandruIordache-MRM Jan 2, 2026
f8846b0
Fix: override Clerk checkout drawer sizing via stable cl-* classes
AlexandruIordache-MRM Jan 2, 2026
1915d2a
Revert "Fix: override Clerk checkout drawer sizing via stable cl-* cl…
AlexandruIordache-MRM Jan 2, 2026
c2d59b2
Revert "Fix: style Clerk checkout drawer using stable cl-* classes (s…
AlexandruIordache-MRM Jan 2, 2026
7c94976
Revert "Fix: use Clerk checkoutProps appearance to size checkout drawer"
AlexandruIordache-MRM Jan 2, 2026
2c8df9a
Chore: remove subscribe-web viewport head override
AlexandruIordache-MRM Jan 2, 2026
02e7735
Fix: avoid billing plan fetch on SignedOut subscribe-web
AlexandruIordache-MRM Jan 2, 2026
ced9f6e
Fix: use Clerk user name on Home and persist locally
AlexandruIordache-MRM Jan 2, 2026
0374900
UI: center flows list container
AlexandruIordache-MRM Jan 2, 2026
dd987c5
Fix: remove invalid eslint rule directive on Home
AlexandruIordache-MRM Jan 2, 2026
bca9604
UI: redesign subscribe page to match Clerk pricing card
AlexandruIordache-MRM Jan 2, 2026
7b37b84
UX: return to app after checkout and restore previous page
AlexandruIordache-MRM Jan 2, 2026
8f0b1cf
Fix: make subscribe-web return flow export-safe (no useSearchParams)
AlexandruIordache-MRM Jan 2, 2026
45e7cb5
Fix: reliable return from checkout to previous page
AlexandruIordache-MRM Jan 2, 2026
8f4d768
Fix: prevent subscribe trap while entitlements sync
AlexandruIordache-MRM Jan 3, 2026
f6aa2c7
Fix: unwrap checkout return path and improve return-to-app fallback
AlexandruIordache-MRM Jan 3, 2026
91c6592
Fix: prevent back from practice returning to subscribe
AlexandruIordache-MRM Jan 3, 2026
c622f85
First draft of bilgingual and superadmin features ready to test
AlexandruIordache-MRM Jan 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .clerk/.tmp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

## DO NOT COMMIT
This directory is auto-generated from `@clerk/nextjs` because you are running in Keyless mode. Avoid committing the `.clerk/` directory as it includes the secret key of the unclaimed instance.

1 change: 1 addition & 0 deletions .clerk/.tmp/keyless.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"publishableKey":"pk_test_bGlrZWQtamF2ZWxpbi02LmNsZXJrLmFjY291bnRzLmRldiQ","secretKey":"sk_test_e8dSaISCl0dIAbCRiHba1VhIrA1w8dfC9Bs2oZ5dFF","claimUrl":"https://dashboard.clerk.com/apps/claim?token=8a9lyxhq1f7tw70fxjabtor0finukxcsilfzefrp","apiKeysUrl":"https://dashboard.clerk.com/apps/app_37RA7v85L1UhcPG9G5373cbssXO/instances/ins_37RA7sD9nohiRs5A4hY0B9S0wxx/api-keys"}
4 changes: 4 additions & 0 deletions .clerk/.tmp/telemetry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"firedAt": "2025-12-27T17:10:41.974Z",
"event": "KEYLESS_ENV_DRIFT_DETECTED"
}
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,19 @@ tsconfig.tsbuildinfo

# vercel
.vercel

# clerk (auto-generated, contains secret keys)
.clerk

# local tooling (do not commit)
.tools

# local npm cache (do not commit)
.npm-cache/

# gradle caches (do not commit)
.gradle/

# android signing (do not commit)
*.jks
android/keystore.properties
165 changes: 128 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,69 +1,160 @@
# Next.js + Tailwind CSS + Ionic Framework + Capacitor Mobile Starter
# FlowBalance — Next.js + Ionic + Capacitor + Clerk

![Screenshot](./screenshot.png)
This repo is a hybrid mobile app (Android/iOS) + web app:
- **UI**: Next.js (App Router) + Ionic React + Tailwind
- **Auth**: Clerk (`@clerk/nextjs`) with **email verification code** (passwordless)
- **Billing**: Clerk Billing (B2C) shown in **external browser** (Google Play compliance)
- **Mobile shell**: Capacitor (WebView pointing at the deployed Next.js app)

This repo is a conceptual starting point for building an iOS, Android, and Progressive Web App with Next.js, Tailwind CSS, [Ionic Framework](https://ionicframework.com/), and [Capacitor](https://capacitorjs.com/).
The project is intentionally built to avoid “spaghetti” workarounds: we prefer Clerk’s prebuilt components and documented configuration over custom auth UIs.

Next.js handles the production React app experience, Tailwind can be used to style each page of your app, Ionic Framework provides the cross-platform system controls (navigation/transitions/tabs/etc.), and then Capacitor bundles all of it up and runs it on iOS, Android, and Web with full native access.
---

See this blog post for an overview of the stack and how it all works: <https://dev.to/ionic/build-mobile-apps-with-tailwind-css-next-js-ionic-framework-and-capacitor-3kij>
## Fast commands

## Usage

This project is a standard Next.js app, so the typical Next.js development process applies (`npm run dev` for browser-based development). However, there is one caveat: the app must be exported to deploy to iOS and Android, since it must run purely client-side. ([more on Next.js export](https://nextjs.org/docs/advanced-features/static-html-export))
```bash
npm run dev
```

To build the app, run:
```bash
npm run make-android
```

```bash
npm run build
npm run make-android-release
```

All the client side files will be sent to the `./out/` directory. These files need to be copied to the native iOS and Android projects, and this is where Capacitor comes in:
### One-command “commit & deploy to Vercel”

We added a helper script:

```bash
npm run sync
npm run vercel -- "your commit message"
```

Finally, use the following run commands to run the app on each platform:
This runs: `git add .` → `git commit -m ...` → `git push origin main`.

---

## Architecture (how routing works)

This repo uses Ionic’s router for the in-app experience, and Next routes for auth + web-only pages.

- **Main app shell**: `components/AppShell.tsx`
- Ionic routes: `/home`, `/flows`, `/progress`, `/settings`
- **Next routes**:
- `/sign-in` → `app/sign-in/[[...sign-in]]/page.tsx` (Clerk `<SignIn />`)
- `/sign-up` → `app/sign-up/[[...sign-up]]/page.tsx` (Clerk `<SignUp />`)
- `/subscribe-web` → `app/subscribe-web/page.tsx` (Clerk `<PricingTable />`, web-only)
- `/post-signup-redirect` → `app/post-signup-redirect/page.tsx` (legacy redirect helper; keep unless you remove env/dashboard redirects)

---

## Clerk: rules of engagement (important)

### What we want
- **No password sign-up** (email verification code only)
- **No custom auth forms** unless Clerk prebuilt cannot support a requirement

### What we actually use in code
- Prebuilt components:
- `@clerk/nextjs` `<SignIn />` and `<SignUp />`
- `fallbackRedirectUrl` + `forceRedirectUrl` props (new API; replaces `afterSignInUrl` / `afterSignUpUrl`)

### Official docs to reference first
- Redirect URLs: `https://clerk.com/docs/guides/development/customize-redirect-urls`
- Billing (B2C): `https://clerk.com/docs/nextjs/guides/billing/for-b2c`

---

## Mobile: Capacitor configuration (critical)

### 1) Keep navigation inside the app WebView
When `server.url` points to a remote domain, that domain **must** be included in `server.allowNavigation` or Capacitor will open it externally.

Config lives in:
- `capacitor.config.json` (source of truth)
- generated copies under `android/.../capacitor.config.json` and `ios/.../capacitor.config.json` (sync keeps them updated)

### 2) Do NOT enable `CapacitorHttp` for Clerk
**Root cause of the “mobile WebView shows Email+Password (missing Clerk footer) vs browser shows correct passwordless sign-up”**:
when `CapacitorHttp` is enabled, Clerk’s requests go through native HTTP, which breaks the WebView cookie/session model Clerk expects.

Keep this setting:
- `plugins.CapacitorHttp.enabled = false`

If you change Capacitor config, always sync:

```bash
npm run ios
npm run android
npx cap sync android
```

## Livereload/Instant Refresh
---

To enable Livereload and Instant Refresh during development (when running `npm run dev`), find the IP address of your local interface (ex: `192.168.1.2`) and port your Next.js server is running on, and then set the server url config value to point to it in `capacitor.config.json`:
## Billing / subscriptions (Google Play compliance)

```json
{
"server": {
"url": "http://192.168.1.2:3000"
}
}
```
### Requirement
**Payments must happen outside the app WebView**.

### Current approach
- In-app buttons open the **system browser** to:
- `https://flowbalance-jdk.vercel.app/subscribe-web`
- We pass a **Clerk sign-in token** so the browser page is authenticated:
- `app/api/create-sign-in-token/route.ts`
- The native app opens: `/subscribe-web?__clerk_ticket=...`
- The web page consumes the ticket using `useSignIn().signIn.create({ strategy: 'ticket', ticket })`

Key files:
- `components/pages/Settings.tsx` (“Manage Subscription”)
- `components/PaywallModal.tsx` (premium upsell → external browser)
- `helpers/openExternal.ts` / `helpers/openSubscriptionPage.ts`
- `app/subscribe-web/page.tsx`

Note: this configuration wil be easier in Capacitor 3 which [recently went into beta](https://capacitorjs.com/blog/announcing-capacitor-3-0-beta).
---

## API Routes
## Known gotchas (and how we avoid them)

API Routes can be used but some minimal configuration is required. See [this discussion](https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter/issues/4#issuecomment-754030049) for more information.
### Next.js hydration errors
Don’t render `window.location`, `navigator.userAgent`, etc. directly into JSX that’s server-rendered. Capture them in `useEffect` instead.

## SEO & Static Hosting
### Ionic SSR warnings
Sometimes `<ion-*>` elements can warn about extra `class` attributes during hydration. Avoid putting Tailwind `className` directly on Ionic web components when it causes warnings; put styling on wrappers.

- **Is the exported PWA crawlable?** By default this starter renders everything on the client (see `components/AppShell.tsx`), so the static build contains a minimal HTML shell that immediately hands off to JavaScript. Search engine bots that depend on server-rendered HTML will not see meaningful page content, so the project is not SEO-friendly out of the box. If you need full SEO support, SSR/SSG needs to be working on the routes you want indexed or using a parallel, SEO-optimized web surface, but take a look at the below caveat about this project.
- **Can I host the export as static HTML?** Yes. `next.config.js` sets `output: 'export'`, so `npm run build` writes a fully static bundle to the `out/` directory. You can deploy those files to any static host (e.g. Vercel static, Netlify, S3, GitHub Pages) or let Capacitor copy them into the native shells.
---

## Caveats
## Debugging utilities

One caveat with this project: Because the app must be able to run purely client-side and use [Next.js's Export command](https://nextjs.org/docs/advanced-features/static-html-export), that means no Server Side Rendering in this code base. There is likely a way to SSR and a fully static Next.js app in tandem but it requires [a Babel plugin](https://github.com/erzr/next-babel-conditional-ssg-ssr) or would involve a more elaborate monorepo setup with code sharing that is out of scope for this project.
We keep the debug UI **as an optional component**:
- `components/DebugInfoBox.tsx`

Additionally, Next.js routing is not really used much in this app beyond a catch-all route to render the native app shell and engage the Ionic React Router. This is primarily because Next.js routing is not set up to enable native-style transitions and history state management like the kind Ionic uses.
Add it temporarily to any client page when debugging, then remove it for design work.

## What is Capacitor?
---

You can think of [Capacitor](https://capacitorjs.com/) as a sort of "electron for mobile" that runs standard web apps on iOS, Android, Desktop, and Web.
## Development workflow + user preferences (for future agents)

### Preferences (must follow)
- **Use official docs** before proposing changes. If unsure, link the exact doc page.
- **Don’t invent** Clerk behavior or props; verify against docs.
- **Don’t build custom auth UIs** unless explicitly requested (use Clerk prebuilt components).
- **Always give copy/paste commands** using:
- `git add .`
- or the preferred one-liner: `npm run vercel -- "message"`
- Keep changes clean and reversible; avoid “one-off hacks” that linger.

### Style preference
Tailwind-first styling. Only use raw CSS when necessary for Ionic theming or truly global concerns.

---

## Environment variables (minimum)

Set these in both local `.env.local` and Vercel:

```bash
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
```

Capacitor provides access to Native APIs and a plugin system for building any native functionality your app needs.
If you use any redirect env vars, document them here and ensure they match existing routes. Avoid deprecated `NEXT_PUBLIC_CLERK_AFTER_*` variables.

Capacitor apps can also run in the browser as a Progressive Web App with the same code.
3 changes: 3 additions & 0 deletions android/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions android/.idea/AndroidProjectSystem.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions android/.idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions android/.idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions android/.idea/deviceManager.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions android/.idea/migrations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions android/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions android/.idea/runConfigurations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 28 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
apply plugin: 'com.android.application'

android {
namespace "com.example.app"
namespace "com.flowapp.app"
compileSdkVersion rootProject.ext.compileSdkVersion

buildFeatures {
buildConfig true
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}

defaultConfig {
applicationId "com.example.app"
applicationId "com.flowapp.app"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
Expand All @@ -16,8 +26,24 @@ android {
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
}

signingConfigs {
release {
def keystorePropertiesFile = rootProject.file("keystore.properties")
def keystoreProperties = new Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
}
}
}

buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
Expand Down
Loading