PamperHive — Privacy Policy
What this is: the privacy policy for the PamperHive Android app and the PamperHive API. It is written to be read on a phone, not by a lawyer.
Last checked against the code: 9 August 2026, against V1__init.sql, server/src/main/kotlin/**, feature/**, shared/** and composeApp/src/androidMain/AndroidManifest.xml.
Effective from: ⚠ [[PLACEHOLDER: publication date — fill in on the day this goes live on the website]]
Every statement below describes what the software actually does today. Where something is built but not yet switched on, it says so. Where a real-world value does not exist yet, it is marked
[[PLACEHOLDER: …]]and listed at the end of this document.
Who we are
PamperHive is an appointment booking app for barbershops in Alappuzha, Kerala. You find a shop near you, pick a barber, a service and a time, and book. No money passes through the app — you pay the shop in cash at the chair.
- Operated by: ⚠ [[PLACEHOLDER: registered legal entity name]]
- Registered address: ⚠ [[PLACEHOLDER: registered address in India]]
- Contact for anything in this policy: aswincodename47@gmail.com
This policy is written for the Digital Personal Data Protection Act, 2023 (DPDP Act). Under that Act you are the Data Principal and we are the Data Fiduciary for the data described here.
The short version
- We ask for your phone number. That is the only thing we require.
- We ask for your approximate location, only to sort shops by distance. You can say no and pick your area from a list instead.
- If you post a review you may attach up to three photos, and you tick a box first that tells you where they will appear and under what name.
- The shop you book with sees your name and phone number, because they may need to ring you.
- Your review is public, signed with your first name and last initial — "Amit D.", never "Amit Deshpande".
- You can delete your account from inside the app. Your reviews stay up without your name, because they are part of the shop's record.
- We do not sell your data. We do not run advertising. There is no advertising ID, no tracking SDK and no analytics SDK in the app today.
What we collect, and why
1. Your phone number — required
We ask for your phone number when you tap Confirm booking, not before. You can browse shops, look at reviews and check availability without an account.
We send a six-digit code by SMS and you type it back. That is the whole login — there is no password and no separate signup. The first time a number verifies, an account is created for it.
We use your number to:
- sign you in and keep you signed in;
- give it to the shop you booked with, so they can call you if something changes;
- send you booking messages (see Messages we send you below).
How the code is stored. We never store the code itself. We store a SHA-256 hash of it, an expiry time, an attempt counter, and the network address the request came from. The hash cannot be turned back into the code.
In the code: users.phone in V1__init.sql; otp_challenges in the same file; OtpService.kt.
2. Your name — optional
The app has a name field on your account. Today the customer app has no screen that lets you type it, so for most customers it is empty and the shop simply sees "Customer" next to your booking.
If a name is set, it is used in two places: the shop's day screen shows it in full, and your public reviews show it abbreviated (see Reviews are public).
If you are a shop owner, the setup flow asks you to type your staff members' display names and to add their photos. That is information about other people that you are giving us, and you are responsible for having their agreement to publish it.
In the code: users.name in V1__init.sql; MeController.kt (PATCH /me); feature/ownersetup/.
3. Your approximate location — optional
The app asks Android for approximate location only (ACCESS_COARSE_LOCATION). It does not ask for precise location. Android shows you which one an app asked for, and we deliberately ask for the less precise one, because the product sorts shops into 500-metre distance bands and precise location would be more than we use.
We read your last known position from the phone, not a live GPS fix. It is sent to our server so it can return shops near you, ordered by distance band.
Location is asked for at the point it is used, with the reason on screen — never on first launch. If you say no, the app still works: you pick your area from a list (Komalapuram, Pathirappally, Aryad, Alappuzha and so on) and search from there.
We do not store your location on our server when you search. It is used to answer the search and not written to the database.
One exception. If you look somewhere we have no shops and tap "Notify me", we save that point so we know where to sign shops up next. That row records the coordinates, the kind of shop you were looking for, and your account id if you are signed in. It does not contain your phone number — the app does not send one on that request.
In the code: AndroidManifest.xml; Location.android.kt; DiscoveryStore.kt; DemandController.kt; demand_signals in V1__init.sql.
4. Your bookings
For every booking we store which shop, which barber, which service, the time, the price the shop was charging at that moment, and what happened to it — it went ahead, you cancelled, the shop cancelled, or you were marked absent.
We also store whether you tapped "Still coming?" on the two-hour reminder, and, if a shop marked you absent and you disputed it, that you disputed it and what an administrator decided.
We keep this because it is your booking history, it is the shop's record of its day, and because a review can only be written against a real, completed visit.
In the code: bookings in V1__init.sql.
5. Your reviews and photos
After a visit you can leave a rating for the shop, an optional rating for the barber, a comment, and up to three photos.
Photos go straight from your phone to our storage bucket using a one-time upload link — the bytes do not pass through our API server. Before you can attach any photo, you tick a box that names the shop page the photo will appear on and the name it will appear under. The server refuses the review if that box was not ticked; it does not simply trust the app.
Status today: the photo upload feature is fully written but the storage account is not connected yet, so the app currently cannot complete an upload. It becomes live the moment that account is configured on the server — with no new app release. Treat the photo sections of this policy as describing what happens from that moment.
In the code: ReviewController.kt; MediaSigner.kt; review_photos in V1__init.sql; the consent copy in ReviewScreen.kt.
6. Network address, for abuse protection
When you ask for a login code we record the network (IP) address the request arrived from, so that one machine cannot request codes for thousands of phone numbers. We do not use it for anything else, and we do not use it to work out where you are.
Being honest about this: our hosting provider sits in front of the API, and today the address we actually record is usually the provider's own edge address rather than yours. We record it either way and we are telling you it is stored.
In the code: otp_challenges.request_ip; ClientIpResolver.kt.
7. Things stored on your phone only
The app keeps a small cache so it is usable on a bad connection: shops you have looked at, your recent search, and your own booking list. It also keeps your sign-in tokens in Android's encrypted preference storage.
Signing out wipes all of it. Phones are shared here and that matters.
In the code: Cache.sq; Platform.android.kt.
What we do not collect
None of the following is collected by the app, and there is no code in it that could:
- No payment information. The app never touches money; you pay the shop in cash. There is no card, no UPI, no wallet, no deposit.
- No email address.
- No contacts, no calendar, no files, no microphone, no camera roll scanning. The app requests exactly two Android permissions: internet and approximate location.
- No advertising ID. No advertising or marketing profiling of any kind.
- No analytics SDK and no crash-reporting SDK. There is no PostHog, no Sentry, no Firebase and no Google Analytics in the app today. If that ever changes, this policy changes with it, in the same release.
- No precise location.
- No health data, no biometric data.
- No in-app chat, so there are no messages to collect.
Who sees your data
The shop you book with
When you book, the shop's owner and managers see, on their day screen: your name (if you have set one), your phone number, the service, and the time. They can tap the number to ring you.
This is the point of the product — a shop that cannot reach you cannot tell you the barber is running an hour late. Booking a shop is you asking us to give them that. The same applies if you join a waiting list for a slot: the shop sees your name and number on the list until you leave it.
In the code: TodayDao.kt.
Everyone, for reviews
Reviews are public. Anyone using the app — or anyone calling the public reviews endpoint — sees the rating, the comment, the photos, which barber it was about, whether the visit was verified, and the date.
Your name is published abbreviated. "Amit D.", never "Amit Deshpande". A single-word name is left as it is, because "Priya ." would be worse than "Priya". This is done on the server, at the point the review is read, so it is true for every reader — the app, the admin panel, and anything else.
If you delete your account, your reviews stay up with no name at all.
In the code: ReviewDao.kt.
Companies that run parts of the service for us
These are service providers processing data on our instructions. They are not allowed to use it for their own purposes.
| Who | What they handle | Status |
|---|---|---|
| Railway | Hosting for the API and the Postgres database — so, all of the data described above | Live. Region: ⚠ [[PLACEHOLDER: Railway deployment region]] |
| Cloudflare R2 | Storage for review photos and shop photos | Configured in code, not connected yet. Bucket location: ⚠ [[PLACEHOLDER: R2 bucket jurisdiction]] |
| SMS provider | Delivering your login code and booking messages | Not chosen yet — MSG91. No SMS is being sent at all today (see below) |
| Google Play | Distributing the app | Live |
We do not sell your data, we do not share it with data brokers, and we do not share it with advertisers. There is nobody else.
When you leave the app. Three buttons hand you over to another app on your phone: the shop's phone number opens your dialler, the shop's address opens your map app, and Contact support opens WhatsApp. We do not send anything to those apps beyond the number or the location you tapped, and once you are in them you are covered by their privacy policies, not ours.
Law
We will hand over data if we are legally required to — a court order, or a lawful demand from an authority entitled to make one.
Messages we send you
Every message the app can send you is one of these six, and no others:
| When | What it says |
|---|---|
| You sign in | Your six-digit code |
| You book | The booking is confirmed, and what you will pay at the shop |
| Two hours before | A reminder, with "Still coming?" |
| The shop cancels | That they cancelled, and to book another time |
| The shop marks you absent | That they did, and that you can dispute it in the app |
| A slot frees on your waiting list | That it opened, and that it is not held for you |
There is no marketing. There is no promotional SMS. There is no newsletter. The list above is enforced in one file in the code, and a message type that is not on it cannot be sent.
Status today: nothing is being sent. Indian transactional SMS requires TRAI DLT registration of the sender and of every individual template, and that is not complete. Until it is, messages are queued and recorded but not delivered. Push notifications are not connected either.
In the code: NotificationCopy.kt; NotificationService.kt; SmsSender.kt.
Deleting your account
In the app — this works today
Account → Delete my account. You get one confirmation dialog that tells you exactly what happens rather than asking "are you sure".
When you confirm:
- your account is marked deleted immediately, and every device you are signed in on stops working on its very next request;
- every refresh token is revoked, so no session can be renewed;
- registered devices are removed, so no notification can reach you;
- your phone number is freed straight away — you can sign up again with it, and you get a fresh, empty account.
Three things survive, and you should know about them before you tap Delete:
- Reviews you have written stay up, without your name. They are part of the shop's public record, and a system where anyone can erase criticism by deleting their account is a system where reviews mean nothing.
- Bookings you have already made are not cancelled. If you are not going, ring the shop. The shop can still see that booking, with the name and number you gave when you made it, because they need to be able to reach you about an appointment that still exists.
- Your account row is kept in a deleted state rather than erased, so that those reviews still have something to hang from. It still contains your phone number.
The confirmation dialog in the app states points 1 and 2 in exactly these terms.
In the code: MeController.kt (DELETE /me); UserDao.softDelete; AccountScreen.kt.
On the web
Google Play requires a deletion route that works without installing the app.
This does not exist yet. It is blocked on the domain and landing page, which have not been set up. It will live at https://api-production-a07b.up.railway.app/delete-account.html and this policy will be updated with the real address on the day it goes live.
Until then, if you cannot use the app, write to aswincodename47@gmail.com from the phone number on the account and we will do it by hand.
Your rights under the DPDP Act
You can ask us to:
- tell you what data we hold about you and who we have shared it with;
- correct anything that is wrong or out of date;
- delete your data — see above for what that does and does not remove;
- withdraw consent you have given. Withdrawing consent for location just means turning the permission off in Android settings; the app keeps working. Withdrawing consent for the phone number means deleting the account, because without a number there is no account;
- nominate someone to exercise these rights if you die or become incapable of exercising them yourself.
To do any of this, write to aswincodename47@gmail.com.
If we have not dealt with you properly, you can complain to us first, and then to the Data Protection Board of India.
Grievance Officer: Aswin A S, aswincodename47@gmail.com, ⚠ [[PLACEHOLDER: grievance officer postal address]]. (Required both by the DPDP Act and by the IT Rules for a platform that publishes user reviews.)
How long we keep things
Plain answers, including the uncomfortable ones.
| What | How long |
|---|---|
| Your account | Until you delete it. After deletion the row is kept, marked deleted, and still contains your phone number, so that your reviews have an author to anonymise |
| Bookings | Kept. They are the shop's record and your history |
| Reviews and review photos | Kept, and public. Anonymised if you delete your account |
| Login code challenges — phone number, code hash, network address | Currently kept indefinitely. There is no automatic clean-up job for this table yet. We intend to add one; it is written here rather than glossed over |
| Sign-in sessions | Refresh tokens expire after 60 days; access tokens after 15 minutes. All are revoked instantly when you sign out or delete your account |
| Queued messages | Currently kept indefinitely. No clean-up job yet |
| Booking retry keys | Deleted automatically after 24 hours |
| "Notify me" location signals | Kept |
| Administrator action records | Kept |
Where the table says "no clean-up job yet", that is a description of the code as it stands on the date at the top of this document, not a promise about the future in either direction.
How we protect it
- Everything between the app and our server travels over HTTPS.
- Your sign-in tokens are held in Android's encrypted preference storage, not in plain preferences — a rooted phone should not be a free account.
- Login codes are stored as SHA-256 hashes, never in readable form. So are refresh tokens.
- Sessions can be revoked from the server, which is what makes "delete my account" mean something rather than "wait fifteen minutes".
- Login codes are rate-limited per phone number, and expire in five minutes after five wrong attempts.
- Phone numbers are masked in our server logs.
What we do not claim: we have not had an independent security audit, and the database does not currently have managed backups. Both are noted here because a policy that only lists strengths is not information.
Children
PamperHive is not intended for anyone under 18, and we do not knowingly create accounts for children. A parent booking a child's haircut is booking on their own account, with their own number — the app never asks about the person in the chair.
Changes to this policy
The app cannot be updated over the air — every change ships through Google Play review. So when this policy changes we will post the new version at https://api-production-a07b.up.railway.app/privacy.html with a new date at the top, and, for any change that affects what we collect, we will tell you in the app.
Placeholders to fill before this is published
Every value in this document that does not exist yet, in one place. None of these may be guessed.
| # | Placeholder | Blocked on |
|---|---|---|
| 1 | Registered legal entity name | Company registration |
| 2 | Registered address in India | Company registration |
| 3 | Privacy contact email | Domain + mailbox |
| 4 | Publication / effective date | Publication |
| 5 | Privacy policy URL | Domain and landing page (Week 0) |
| 6 | Web account-deletion URL | Domain and landing page (Week 0) |
| 7 | Grievance Officer — name, email, postal address | Appointment of an officer |
| 8 | Railway deployment region | Read it off the Railway project |
| 9 | Cloudflare R2 bucket jurisdiction | R2 bucket creation (Week 0) |
| 10 | SMS provider name — MSG91 or Fast2SMS | Provider decision + DLT registration |
Statements that must be re-checked before publication
These are true on the date at the top and will stop being true when the work they describe lands:
- "No analytics SDK and no crash-reporting SDK" — false the day PostHog or Sentry is added.
- "The photo upload feature … cannot complete an upload" — false the day the R2 credentials are set on the server. No app release is needed for that, so this sentence can go stale without anyone touching the app.
- "Nothing is being sent" (SMS) — false the day DLT registration clears.
- "Push notifications are not connected" — false the day FCM is added.
- "The customer app has no screen that lets you type [a name]" — false the day a profile editor ships.
- "The app requests exactly two Android permissions" — re-check the manifest.