Google Drive
When a contract finishes signing (via DocuSign or the share-token flow), the final signed PDF can be auto-archived to your Google Drive in a folder of your choice. Per-user — each staff member connects their own Drive.
Connecting
Integrations → Google Drive → Connect opens Google's OAuth. Scopes:
drive.file— create / read / update only files the app creates (no full-Drive access)userinfo.email/userinfo.profile— identity binding
Drive uses the drive.file scope rather than full drive — this means Kinderpedia can only see / modify files it creates. Your other Drive content is invisible to us by design.
When the Kinderpedia admin has configured a separate Google OAuth app for Drive, the consent screen shows only Drive scopes. Otherwise the Drive consent appears alongside Calendar (Google merges scope grants per app). Either way the Drive scope itself is unchanged.
Picking a folder
After connect, the integration config has Default folder. Click Pick folder… to open Google's folder picker — we generate the picker URL with drive.file scoped access, you pick (or create) a folder, and your selection is saved on your personal integration record.
You can:
- Pick a root-level folder (
My Drive / Admissions Contracts) - Pick a nested folder (
My Drive / 2026 / Signed contracts) - Pick a Shared Drive folder (the picker shows Shared Drives the user has access to)
The folder is shown by name on the tile. Re-pick anytime to change.
What gets pushed
When a contract reaches status = signed:
GoogleDriveAutoSyncService::pushSignedContract($contract, $user)runs.- Downloads the signed PDF from the contract's S3 URL.
- Uploads to Google Drive via
files.createwith multipart upload (file + metadata) targeting the user'sdrive_folder_id. - Sets the Drive file's name to
{contract_number} - {lead_name}.pdf. - Stores the resulting Drive file ID on
contracts.drive_file_id(also writesdrive_urlfor one-click open).
Each Drive push is scoped to the user who originally sent the contract. Not the lead-assigned user, not all admins — just the sender. If Sender A sends a contract, only Sender A's Drive gets a copy.
Multi-user pushes
A single contract pushes to one Drive (the sender's). If your team needs every signed contract to land in a shared folder, the right setup is:
- Sender connects their Drive.
- Sender picks a folder that lives on a Shared Drive they have write access to.
- Once uploaded, the file inherits Shared Drive ACLs — everyone with Shared Drive access sees it.
We don't fan-out the upload to N users' Drives (that would double-store + duplicate the audit trail).
Manual archive
For older contracts signed before Drive was connected, the contract detail page has a Save to Drive button (visible to the sender). Click → archives the existing signed PDF retroactively. Same flow, just triggered on-demand.
Token refresh + watch
Drive doesn't need a watch channel — we don't read changes from Drive, only write. GoogleDriveTokenManager::getAccessToken() mirrors the Calendar token manager (60s safety window, refresh on demand).
File naming
Files use {contract_number} - {lead_name}.pdf by default. If a name collision happens (re-archiving same contract), we append a -<short_random> suffix so we never overwrite an existing Drive file.
Custom naming patterns are not currently configurable.
What about contract attachments?
Only the signed PDF is pushed to Drive. Supplementary files (DocuSign Certificate of Completion, ancillary uploads attached to the contract) are not archived. Those stay on Kinderpedia's S3.
Disconnecting
Disconnect clears the credentials + folder ID. Already-archived files stay in your Drive — we don't delete anything. Future signed contracts simply skip the Drive push.
Common errors
| Symptom | Likely cause |
|---|---|
| Folder picker won't open | Pop-up blocker. Allow pop-ups for your Kinderpedia domain. |
| Push fails with "insufficient_permissions" | drive.file was downgraded somehow, or you picked a folder in a Shared Drive you don't have write access to. |
| Push silently no-ops | Sender didn't connect Drive. Auto-archive is per-user — check the sender's integration tile. |
| Duplicate files in folder | Manual + auto archive both ran. Both succeeded; both files exist. Delete the dupe manually. |
| File appears in My Drive root, not picked folder | drive_folder_id was cleared (re-pick). Falls back to root. |
Privacy
The drive.file scope is the minimum-access scope Google offers for app uploads. Kinderpedia cannot:
- List your other Drive files
- Read files you didn't have us create
- Share files with others (we don't call
permissions.create) - Delete files (we never call
files.delete)
If Google ever rolls out a more-restrictive scope, we'll switch — drive.file is currently the tightest.