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.

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


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:

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:


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.

WhoWhat they handleStatus
RailwayHosting for the API and the Postgres database — so, all of the data described aboveLive. Region: ⚠ [[PLACEHOLDER: Railway deployment region]]
Cloudflare R2Storage for review photos and shop photosConfigured in code, not connected yet. Bucket location: ⚠ [[PLACEHOLDER: R2 bucket jurisdiction]]
SMS providerDelivering your login code and booking messagesNot chosen yet — MSG91. No SMS is being sent at all today (see below)
Google PlayDistributing the appLive

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:

WhenWhat it says
You sign inYour six-digit code
You bookThe booking is confirmed, and what you will pay at the shop
Two hours beforeA reminder, with "Still coming?"
The shop cancelsThat they cancelled, and to book another time
The shop marks you absentThat they did, and that you can dispute it in the app
A slot frees on your waiting listThat 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:

Three things survive, and you should know about them before you tap Delete:

  1. 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.
  2. 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.
  3. 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:

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.

WhatHow long
Your accountUntil 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
BookingsKept. They are the shop's record and your history
Reviews and review photosKept, and public. Anonymised if you delete your account
Login code challenges — phone number, code hash, network addressCurrently 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 sessionsRefresh tokens expire after 60 days; access tokens after 15 minutes. All are revoked instantly when you sign out or delete your account
Queued messagesCurrently kept indefinitely. No clean-up job yet
Booking retry keysDeleted automatically after 24 hours
"Notify me" location signalsKept
Administrator action recordsKept

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

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.

#PlaceholderBlocked on
1Registered legal entity nameCompany registration
2Registered address in IndiaCompany registration
3Privacy contact emailDomain + mailbox
4Publication / effective datePublication
5Privacy policy URLDomain and landing page (Week 0)
6Web account-deletion URLDomain and landing page (Week 0)
7Grievance Officer — name, email, postal addressAppointment of an officer
8Railway deployment regionRead it off the Railway project
9Cloudflare R2 bucket jurisdictionR2 bucket creation (Week 0)
10SMS provider name — MSG91 or Fast2SMSProvider 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: