feat: Google Drive Integration#612
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
|
| private static final List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE); | ||
| private static final String CREDS_FILE_PATH = "/credentials.json"; | ||
| private static final String TOKENS_DIR_PATH = "tokens"; | ||
| private static final String SERVICE_ACCOUNT_PATH = "/service-account.json"; |
There was a problem hiding this comment.
Based on what I checked that is not the best solution because we need to upload the json account for each deployment in fly.io so it is not so simple to make this.
# Production Plan for Google Drive and Email on Fly.io
## Goal
This document describes the production-ready approach for running Google Drive
storage and transactional email in Fly.io without relying on local-only
workarounds such as:
- committing `credentials.json` into the image
- manually copying files into a running Fly machine
- using browser-based OAuth flows on the server
- relying on placeholder mail configuration in `application.yml`
It also explains the code changes needed in the backend and the operational
setup for both development and production environments.
## Short Answer
Google Drive and email are not the same situation in this codebase.
### Google Drive today
The current Google Drive implementation in
`src/main/java/com/wcc/platform/repository/googledrive/GoogleDriveFileStorageRepository.java`
expects:
- a classpath resource `/credentials.json`
- a writable local `tokens/` directory
- an interactive OAuth browser flow if no token exists
That is not production-safe on Fly.io.
## Target Production Architecture
### Google Drive
Replace desktop OAuth credentials with a Google service account and load the
credentials from a filesystem path or environment-provided secret at runtime.
Target outcome:
- no browser auth on the server
- no `tokens/` directory required
- no `credentials.json` bundled into the application JAR
- credentials provided through Fly secrets and written to a runtime path
- Drive folders shared explicitly with the service account identity
## Required Code Changes
### 1. Google Drive: stop loading credentials from the classpath
Current implementation:
- `CREDS_FILE_PATH = "/credentials.json"`
- `GoogleDriveFileStorageRepository.class.getResourceAsStream(CREDS_FILE_PATH)`
This should be replaced by configuration-driven loading.
#### Proposed new properties
Add properties such as:
```yaml
wcc:
google-drive:
auth-mode: service-account
credentials-path: ${GOOGLE_DRIVE_CREDENTIALS_PATH:}
application-name: WCC Backend
Optional future extension:
wcc:
google-drive:
credentials-json-base64: ${GOOGLE_DRIVE_CREDENTIALS_JSON_B64:}Code changes
Modify:
src/main/java/com/wcc/platform/repository/googledrive/GoogleDriveFileStorageRepository.java
Add:
- a configuration properties class, for example:
src/main/java/com/wcc/platform/properties/GoogleDriveAuthProperties.java
Implementation direction:
- remove the desktop OAuth
AuthorizationCodeInstalledAppflow from production - load service account credentials from
GOOGLE_DRIVE_CREDENTIALS_PATH - use Google credentials suitable for server-to-server access
- build the
Driveclient from those credentials directly
The production code should fail fast at startup if:
storage.type=google- but credentials path is missing
- or the credentials file cannot be parsed
2. Google Drive: support profile-based auth modes
Recommended split:
local: allow local filesystem storage by defaultdev: optionally use service-account-based Google Drive if the developer has
the credentials file locallyprodorflyio: only allow service-account mode
This avoids production inheriting local OAuth assumptions.
3. Add startup validation
Add validation so the app fails fast when production configuration is invalid.
Examples:
- if
storage.type=googleandGOOGLE_DRIVE_CREDENTIALS_PATHis missing - if
spring.mail.hostis set butMAIL_USERNAMEorMAIL_PASSWORDis blank - if required Drive folder IDs are missing
This can be implemented with:
@ConfigurationProperties@Validated- bean initialization checks
Google Drive Service Account Setup
1. Create the service account
In Google Cloud Console:
- Open your Google Cloud project
- Go to
IAM & Admin->Service Accounts - Create a new service account
- Give it a clear name such as
wcc-backend-drive-prod - Create a JSON key
- Download the JSON key securely
Do not commit this file to the repository.
2. Share the Drive folders with the service account
This is the critical step that replaces the desktop OAuth user flow.
For each required Google Drive folder:
- Open the folder in Google Drive
- Share it with the service account email address
- Grant the correct access level
Typical minimum access:
Editorfor upload/update flows
Share:
- the environment root folder
- or each specific subfolder the app writes to
3. Record the folder IDs [DONE AND UPDATED TO PROD]
Use the same folder IDs already expected by the app:
- main folder
- resources folder
- events folder
- images folder
- mentor pictures folder
- mentor resources folder
These should remain configuration values, not code constants.
Fly.io Setup
Google Drive secrets
Store the service account JSON in Fly secrets.
Example:
fly secrets set GOOGLE_DRIVE_CREDENTIALS_JSON_B64="$(base64 < service-account.json | tr -d '\n')"At startup:
- create a runtime directory such as
/app/secrets - decode the secret into
/app/secrets/google-drive-service-account.json - set:
[env]
SPRING_PROFILES_ACTIVE = "flyio"
GOOGLE_DRIVE_CREDENTIALS_PATH = "/app/secrets/google-drive-service-account.json"This requires either:
- an entrypoint script
- or a launch command wrapper
Suggested Fly startup flow
Create a startup script that:
- creates
/app/secrets - decodes
GOOGLE_DRIVE_CREDENTIALS_JSON_B64into the credentials file - starts the Java app
Example outline:
#!/bin/sh
set -eu
mkdir -p /app/secrets
if [ -n "${GOOGLE_DRIVE_CREDENTIALS_JSON_B64:-}" ]; then
echo "$GOOGLE_DRIVE_CREDENTIALS_JSON_B64" | base64 -d > /app/secrets/google-drive-service-account.json
fi
exec java -jar app.jarThis is acceptable in production because:
- the secret is injected by Fly
- the file is created at runtime
- the secret is not baked into the image
Recommended Development Setup
Local development for Google Drive
Best default:
- use
storage.type=local
This avoids forcing every developer to configure Google Drive credentials just
to run the app.
If a developer needs to test real Google Drive integration locally:
- use the same service account approach as production
- store the JSON file outside the repository
- point
GOOGLE_DRIVE_CREDENTIALS_PATHat that local file
Do not rely on desktop OAuth as the long-term supported path.
Testing Plan
Dev environment tests
Google Drive
- Start the app with
storage.type=google - Set
GOOGLE_DRIVE_CREDENTIALS_PATHto a valid local service account file - Upload a test file through the relevant API
- Confirm the file appears in the expected Drive folder
- Verify the returned link is accessible as expected
Negative tests:
- missing credentials path
- malformed JSON
- valid credentials but folder not shared with service account
Production tests
Google Drive
- Deploy to Fly with service-account secret configured
- Verify app startup succeeds without OAuth prompts
- Call the upload endpoint with a small test file
- Confirm the file is stored in the correct production Drive folder
- Verify permissions and returned web link
Operational checks:
- restart the Fly machine
- redeploy the app
- confirm uploads still work without any reauthorization
Recommended Implementation Sequence
- Refactor Google Drive auth to service-account-based loading from a configured path
- Remove production dependence on
/credentials.jsonclasspath resource - Add startup validation for missing production secrets
- Add or update integration tests for Drive config loading where practical
- Add deployment documentation for Fly secrets and startup script [done]
- Optionally revisit a dedicated transactional provider if Gmail or Workspace
limits become operationally restrictive
Final Recommendation
Google Drive
Real production fix:
- migrate from desktop OAuth to a Google service account
- load credentials from a Fly secret written to a runtime file
- remove token-store and browser-auth assumptions from server code
|
Hey @dricazenck I didn't have permission to push on this branch, so created another PR: #679 |



Description
Related Issue
Please link to the issue here
Change Type
Screenshots
Pull request checklist
Please check if your PR fulfills the following requirements: