Skip to content

Google Drive (documents)

Every file the system keeps — passports, visas, ID, issued e-tickets and vouchers, group documents, voucher attachments, TDS certificates, incident documents, enquiry and visa-application files, request attachments, payment receipts, chat attachments — is kept in the company Shared Drive Alhuda-Shared-Drive on Google Workspace (alhudatravels.in), and nowhere else. Nothing is kept in Supabase Storage (ACC-074). No file on the drive is shared with anyone (ACC-073).

Who can open a file

Who How
Staff Inside the ERP. Every screen that lists a document has an Open button; the file opens in a viewer on the page (an image, or a PDF in a frame, with Download). The drive-file function checks the viewer holds that record's view permission and hands out a link that lives ten minutes. No Google account is needed.
A traveller or partner Inside the app or the portal, through drive-file, for their own documents only (TRV-011).
Shared Drive members Can also open the drive itself ("Open in Google Drive" in the viewer). Membership is for administering the drive — tidying folders, restoring from the trash — not for everyday reading.
Anyone else Nobody. There is no "anyone with the link" sharing.

How files get there

Only edge functions write to the drive, with a Google Cloud service account that is a member of the Shared Drive (Content manager). A service account has no storage of its own, so the folder must be a Shared Drive, not a folder in someone's My Drive. Every call carries supportsAllDrives=true.

Function Stores Checks
upload-customer-doc a customer's documents customers.edit / customers.create, or the traveller's own record
upload-partner-doc a partner's registration documents the partner's own login; or staff holding partners.edit, who send the agency's id (PTR-087)
upload-employee-doc an employee's documents the person, or admin.users.edit
drive-upload group, voucher, TDS, incident, visa and ticket documents; a customer's request attachments and payment receipts the permission of that screen (ACC-074)
lead-intake files sent with a website enquiry the captcha, then 5 enquiries with files per hour per connection
visa-intake files sent with a website visa application the captcha and the form's rate limits
chat-upload chat attachments a staff login
issue-document issued e-ticket sheets and hotel vouchers; payment receipts tickets.view or hotels.view, with bookings.view; a receipt: finance.view or bookings.view, or the booking's customer or partner (FIN-045)

A PDF or a photo (JPEG, PNG, WebP, HEIC), 10 MB at most; a website form, 20 MB in all.

Folders

Under the Shared Drive's root:

Customers/<name (id)>/            customer documents
Customers/<name (id)>/Requests/   a customer's request attachments
Partners/<agency (id)>/           partner registration documents
Employees/<name (id)>/            employee documents
Visa/<case>/                      visa documents uploaded by staff
Visa/Intake/<name (request)>/     files sent with a website visa application
Tickets/<ticket>/                 ticket documents
Issued/<booking (id)>/            issued e-tickets and hotel vouchers
Groups/<group code (id)>/         group documents
Finance/Vouchers/<voucher (id)>/  voucher attachments
Finance/TDS/<deduction (id)>/     Form 16A certificates
Finance/Receipts/<name (id)>/     receipts a customer uploaded with a payment
Enquiries/<name (lead)>/          files sent with a website enquiry
Incidents/<incident (id)>/        incident documents
Chat/<month>/                     chat attachments

The functions make the folders the first time they need them. Every file of the registry kinds is also recorded in the DriveFile table with its kind and record; drive-file reads the kind from there, never from the caller.

Settings

Where Name Value
Supabase secrets GOOGLE_DRIVE_CLIENT_EMAIL, GOOGLE_DRIVE_PRIVATE_KEY From the service account's JSON key
Supabase secrets GOOGLE_DRIVE_FOLDER_ID The Shared Drive's ID (0APyir2YXbXjdUk9PVA)
Supabase secrets DRIVE_LINK_SECRET A long random string. Signs the ten-minute links drive-file hands out. When it is not set the service role key signs them; set it so the links can be revoked on their own (see below).
Supabase secrets TURNSTILE_SECRET_KEY Already set for the website forms. Without it the website refuses files (a form without files still goes through).
Cloudflare Pages — Nothing. VITE_GOOGLE_CLIENT_ID and VITE_GOOGLE_DRIVE_FOLDER_ID are no longer used: delete them from the project's environment variables. The browser never talks to Google.

drive-file and drive-upload are deployed with verify_jwt = false (supabase/config.toml): the link a viewer opens carries no session, and both functions check the session themselves.

Setting it up

  1. Shared Drive. In Drive: New → Shared drive. Add as members only the people who administer the drive.
  2. Workspace sharing. Admin console → Apps → Google Workspace → Drive and Docs → Sharing settings: sharing outside the domain On (the service account is an outside account), warn ticked, guest accounts off, and "visible to anyone with the link" off. Access checker: recipients only, or alhudatravels.in.
  3. Service account. Google Cloud → enable the Google Drive API → IAM & Admin → Service accounts → create → Keys → Add key → JSON. If key creation is blocked, set the organisation policy Disable service account key creation to Not enforced for the project. Add the service account's email to the Shared Drive as Content manager.
  4. Secrets. Set the three Google secrets from the JSON file and DRIVE_LINK_SECRET (openssl rand -base64 48) — never paste a key into chat or a ticket — then deploy the functions below.
  5. Check. On a test customer, upload a document and open it from the customer's screen as a member of staff who is not a Shared Drive member; confirm in Drive → the file → Share that it is shared with nobody.

Deploying

After a change to any of them, deploy:

for f in drive-file drive-upload upload-customer-doc upload-partner-doc upload-employee-doc \
         lead-intake visa-intake chat-upload issue-document; do
  supabase functions deploy "$f" --project-ref <ref>
done

signed-url was removed (it signed any bucket path); delete it from the project: supabase functions delete signed-url --project-ref <ref>.

Rotating

  • The service account key. Create a new JSON key, set the two secrets again, deploy the functions above, then delete the old key in Google Cloud.
  • The link secret. Set a new DRIVE_LINK_SECRET. Every link already handed out stops working at once; people simply open the file again.

Supabase Storage

Not used. The buckets on production (erp-storage-bucket, incident-documents, traveller-documents) are no longer written or read. Deleting them is the owner's decision; nothing in the system depends on them.

Not built

  • A file removed from a record stays on the drive: a service account cannot delete from a Shared Drive, only move a file to the trash, and the ERP does not do even that on removal. Tidy the folders by hand.
  • Removing a person from the Shared Drive when their ERP login is deactivated is done by hand.