Encryption
🔐 Encrypted in transit
All app, portal, and API traffic runs over TLS (HTTPS). There is no plaintext mode in production.
✉️ Messages encrypted at rest
Parent–driver–school message content is stored encrypted with AES-256-GCM, with a unique nonce and integrity tag per message — a database copy alone cannot read a conversation.
Each school's data is isolated
Every record belongs to exactly one school, and every server request re-checks that the signed-in user's school matches the record — on reads, writes, exports, and live-map subscriptions alike. Exports are scoped deny-by-default: a role only receives the columns and rows its job needs.
We attack this ourselves: an adversarial test suite that tries cross-school reads, stale permissions, and role escalation runs on every change, and the build fails if any of it gets through.
Account security
📱 Two-factor sign-in for school staff
Staff and admin accounts support authenticator-app 2FA (TOTP). School admins can see who has it enabled.
🚫 Brute-force lockout
Repeated failed sign-ins lock the attempt path — while a parent with the correct password always gets in.
⏱️ Short-lived, signed sessions
Access tokens are signed and short-lived; deactivating an account cuts its access — including live bus-location streams — immediately.
Data has a defined lifespan
Trip and location history is deleted automatically after its retention window (by default 730 days after the trip; a school can choose a shorter window, never a longer one). Audit logs are kept longer (default: three years) because they answer "who did what". The sweep is a scheduled job, not a promise.
Under Egypt's Personal Data Protection Law (PDPL), a guardian can request a full export of their data, or erasure — we anonymize personal data within the 90-day legal window, and the erasure survives backups and restores.
Who saw my child's data?
Every time a staff member opens a child's full record or exports personal data, the access is recorded server-side in a sensitive-access register the school can review and show to a parent or regulator. Unusual patterns — one account opening many children's records in a day — are flagged for review.
Our standing commitments
🙅 No ads, ever
We never sell data, never show ads, and never use children's data for marketing. Schools pay for PomNav, and every safety feature is free for every family. Parents may choose optional extras their school didn't include. Safety is never one of them.
🎥 No session-recording of minors
No analytics tool that records screens, keystrokes, or sessions runs in the parent or student apps.
🖼️ Student media is never public
Photos and documents about students are only reachable through authenticated, school-checked, logged requests — never a public link or bucket. Our build fails automatically if anyone wires a public path.
Sub-processors
We keep the list short, and services stay disabled until a school turns them on:
| Service | Purpose | When active |
|---|---|---|
| Cloudflare | DNS, HTTPS termination and content delivery for this site and the API | Always |
| Railway | Runs the application servers and hosts the database where records are stored | Always |
| Expo | Push-notification delivery to phones | Always |
| Resend | Sending email — password resets, invitations, receipts | Only if the school enables email |
| Paymob / Fawry | Card and kiosk fee payments | Only if the school enables online payments |
| SMS / WhatsApp provider | Text-message delivery of alerts and codes | Only if the school enables that channel |
| Grafana Cloud (Loki) | Stores operational warning and error logs so faults can be investigated | Only if log shipping is configured |
| Google Sheets | Reads a school-owned sheet to import the student roster | Only if the school enables roster import |
| GitHub | Stores the nightly encrypted database backup for 7 days | Always |
| CARTO | Supplies the map background; receives the device’s IP address and the map area shown | Always, unless the school sets its own map tile server |
| Google Maps | Opens driving directions for the driver; receives the next pickup point’s coordinates | Only when a driver taps “navigate to next stop” |