# BigBrainParking

An unofficial, de-Googled client for the ParkSmarter (IPS Group) parking system,
built to run on **GrapheneOS** with **UnifiedPush** notifications and distributed
via **Obtainium** — no Google Play Services, no Firebase, no app store.

## Install it (users)

BigBrainParking installs and updates through **Obtainium** — no Google Play, no account.
Works on GrapheneOS. On your phone (with Obtainium installed), tap:

**➕ [Add BigBrainParking to Obtainium](obtainium://add/https://git.mowden.top/hank/BigBrainParking)**

or follow **[INSTALL.md](INSTALL.md)** for the manual steps.

## Monorepo layout

```
bigbrainparking/
├── parksmarter-client/   # Zero-dep TypeScript API client (reverse-engineered, live-verified)
├── app/                  # Expo / React Native app (BigBrainParking)
└── .gitea/workflows/     # CI: build signed APK -> publish release for Obtainium
```

- **`parksmarter-client`** — the API layer. All ~40 endpoints, the custom-header auth
  model, and response models (most verified against production). Runs anywhere; the app
  imports it directly. See its own README for the API details.
- **`app`** — the phone app. React Native (Expo prebuild), MapLibre maps, VisionCamera QR
  scanning, expo-secure-store token storage, local session-expiry reminders, and
  UnifiedPush wiring.

## Features

| Feature | Status | Notes |
| --- | --- | --- |
| Phone + password login | ✅ wired | tokens in OS keystore |
| Map of nearby meters (clickable, zoom, live GPS) | ✅ wired | MapLibre + OpenFreeMap tiles (no key) |
| "Near my last location" proximity search | ✅ wired | caches last GPS fix |
| QR kiosk scan → meter lookup | ✅ wired | on-device VisionCamera |
| Save / share kiosks | ✅ wired | local (no server favorites API exists) |
| Active / past sessions | ✅ wired | list views |
| Start a paid session | 🟡 gated | flow wired to `postStartParkingSession`, disabled pending review (real charge) |
| Session-expiry reminders | ✅ wired | **local** on-device notifications — no server, no push |
| UnifiedPush (ntfy) | ⚪ optional | not needed for reminders; stub for future server-initiated msgs |

## Build & run (dev)

Requires Node 20, JDK 17, Android SDK, and a GrapheneOS device (or any Android device)
with USB debugging.

```bash
npm install                                   # installs both workspaces
npm run build --workspace parksmarter-client  # compile the client
cd app
npx expo prebuild --platform android          # generate native project
npx expo run:android                          # build + install a dev client
```

The app talks to prod (`apiv2.parksmarter.com`) by default — change `extra.psEnvironment`
in `app/app.json` to point elsewhere.

## Notifications on GrapheneOS

Session-expiry reminders are scheduled **entirely on-device** from each session's end time
(Android `AlarmManager`, via expo-notifications) — no server, no push, no FCM, no Play
Services. They work fully offline. Configure the lead time (default 15 min) in
**Account → Notifications**, where a **"Send a test reminder"** button lets you confirm it
fires on your phone. UnifiedPush (ntfy) is wired only as an optional, no-op stub for any
*future* server-initiated messages; nothing time-based needs it.

## Distribution via Obtainium (self-hosted)

Tag a release and CI builds a signed APK and publishes it to this repo's releases; your
phone's Obtainium tracks the repo and offers updates. See
[`docs/DISTRIBUTION.md`](docs/DISTRIBUTION.md) for the full server + CI + keystore setup.
