Skip to content

Conversation

@ReeseAstor
Copy link
Owner

@ReeseAstor ReeseAstor commented Sep 28, 2025

Integrate Supabase, Notion, and Google Drive to transform the workspace into a cloud-integrated application.

This PR replaces the local SQLite database with Supabase for cloud storage and authentication, and adds Notion and Google Drive integrations for enhanced collaboration, document backup, and data synchronization across companies, novels, and credit memos.


Open in Cursor Open in Web


Note

Migrates backend to Supabase with JWT auth and adds Notion + Google Drive integrations (OAuth, sync/backup), new sync endpoints, and auth/integration UI.

  • Backend:
    • Supabase Migration: Replace SQLite with Supabase; add RLS schema (supabase/schema.sql), admin/client setup (config/supabase.js), and JWT auth middleware (middleware/auth.js); add /auth/* and profile endpoints.
    • Integrations & Sync: Add Notion (config/notion.js) and Google Drive (config/googleDrive.js, OAuth callback) with centralized services/syncService.js (create/update, backups, sync logs, status); new endpoints for sync status and manual sync.
    • APIs Updated: Companies, financial upload, credit memos, novels/chapters/beats now authenticated and persisted in Supabase; financial docs optionally backed up to Drive.
  • Frontend:
    • Auth & Profile UI: New modal-based sign-in/sign-up, profile/integration settings (public/auth.js), integration status/connect; route calls via authenticatedFetch.
    • Sync UX: UI badges and modal for sync status + manual sync; styling updates.
  • Setup/Config:
    • Add .env.example, detailed SETUP.md; install Supabase/Notion/Google APIs and supporting deps in package.json.

Written by Cursor Bugbot for commit 8d1ab88. This will update automatically on new commits. Configure here.

Co-authored-by: info <info@reeseastor.com>
@cursor
Copy link

cursor bot commented Sep 28, 2025

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

cursor[bot]

This comment was marked as outdated.

@ReeseAstor ReeseAstor marked this pull request as ready for review September 29, 2025 01:02
Copilot AI review requested due to automatic review settings September 29, 2025 01:02
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR transforms the workspace from a local SQLite-based application to a cloud-integrated platform using Supabase, Notion, and Google Drive. The migration introduces user authentication with JWT tokens, external service synchronization, and comprehensive cloud backup capabilities.

  • Replaces SQLite with Supabase for cloud database and authentication
  • Integrates Notion and Google Drive APIs for external data synchronization and backup
  • Adds comprehensive user authentication system with profile management

Reviewed Changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
supabase/schema.sql Defines complete PostgreSQL schema with RLS policies, custom types, and triggers
services/syncService.js Implements synchronization logic between Supabase and external services
server.js Updates server routes to use Supabase authentication and external integrations
public/styles.css Adds modal styling and sync badge components for authentication UI
public/script.js Updates frontend to use authenticated requests and display sync status
public/index.html Adds authentication and profile management modals
public/auth.js Implements client-side authentication and session management
package.json Adds dependencies for Supabase, Notion, Google APIs, and authentication
middleware/auth.js Provides JWT token validation middleware for protected routes
config/supabase.js Configures Supabase client connections
config/notion.js Implements Notion API integration helpers
config/googleDrive.js Provides Google Drive API functionality for file operations
SETUP.md Comprehensive setup guide for all cloud integrations
.env.example Template for required environment variables

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, email, full_name)
VALUES (NEW.id, NEW.email, NEW.raw_user_meta_data->>'full_name');
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function assumes raw_user_meta_data contains a full_name key, but this could be null or missing, potentially causing insert failures. Consider adding a COALESCE or null check.

Suggested change
VALUES (NEW.id, NEW.email, NEW.raw_user_meta_data->>'full_name');
VALUES (NEW.id, NEW.email, COALESCE(NEW.raw_user_meta_data->>'full_name', ''));

Copilot uses AI. Check for mistakes.
try {
await this.logSync(userId, 'company', companyData.id, 'notion', action, 'pending');

const notionResult = await notionHelpers.createCompany(companyData.name, companyData.industry);
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the Notion API call fails, the error message from the catch block may not be user-friendly. Consider wrapping API errors with more descriptive messages for better user experience.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +46
const fileMetadata = {
name: fileName,
parents: folderId ? [folderId] : [process.env.GOOGLE_DRIVE_FOLDER_ID]
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If process.env.GOOGLE_DRIVE_FOLDER_ID is undefined, this will create an array with undefined, potentially causing Google Drive API errors. Add validation to ensure the environment variable is set.

Suggested change
const fileMetadata = {
name: fileName,
parents: folderId ? [folderId] : [process.env.GOOGLE_DRIVE_FOLDER_ID]
// Validate folderId or environment variable
const resolvedFolderId = folderId || process.env.GOOGLE_DRIVE_FOLDER_ID;
if (!resolvedFolderId) {
throw new Error('No Google Drive folder ID provided. Please specify a folderId or set the GOOGLE_DRIVE_FOLDER_ID environment variable.');
}
const fileMetadata = {
name: fileName,
parents: [resolvedFolderId]

Copilot uses AI. Check for mistakes.
Comment on lines +168 to +175
clearInterval(checkAuth);
showSuccess('Google Drive connected successfully!');
updateIntegrationStatus();
} else if (window.location.search.includes('google_auth=error')) {
clearInterval(checkAuth);
showError('Google Drive connection failed');
}
}, 1000);
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This polling mechanism will run indefinitely if the user closes the auth popup without completing authentication, causing a memory leak. Add a timeout to clear the interval after a reasonable duration.

Suggested change
clearInterval(checkAuth);
showSuccess('Google Drive connected successfully!');
updateIntegrationStatus();
} else if (window.location.search.includes('google_auth=error')) {
clearInterval(checkAuth);
showError('Google Drive connection failed');
}
}, 1000);
clearInterval(checkAuth);
clearTimeout(authTimeout);
showSuccess('Google Drive connected successfully!');
updateIntegrationStatus();
} else if (window.location.search.includes('google_auth=error')) {
clearInterval(checkAuth);
clearTimeout(authTimeout);
showError('Google Drive connection failed');
}
}, 1000);
// Add a timeout to clear the interval after 60 seconds
const authTimeout = setTimeout(() => {
clearInterval(checkAuth);
showError('Google Drive authentication timed out. Please try again.');
}, 60000);

Copilot uses AI. Check for mistakes.
const uploadedFile = await this.uploadFile(tempFilePath, fileName, mimeType, novelsFolderId);

// Clean up temp file
fs.unlinkSync(tempFilePath);
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the file upload fails or an exception occurs before this line, the temporary file may not be cleaned up, leading to disk space accumulation. Use try-finally or ensure cleanup happens in all code paths.

Copilot uses AI. Check for mistakes.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Comment on lines +168 to +172
app.get('/auth/google/callback', authenticateToken, async (req, res) => {
try {
const { code } = req.query;
const tokens = await googleDriveHelpers.getTokens(code);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Allow OAuth callback without bearer token

The Google OAuth redirect is wrapped in authenticateToken, but browser redirects from Google never carry the Authorization header you expect. Every /auth/google/callback request will therefore be rejected before the authorization code is exchanged and the tokens written to the profile, so users can never connect Google Drive. Consider identifying the user via an OAuth state parameter or removing the token requirement on this callback.

Useful? React with 👍 / 👎.

} catch (error) {
res.status(400).json({ error: error.message });
}
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Server-Side Signout Not Properly Handled

The /auth/signout endpoint calls supabase.auth.signOut(). This method is for client-side session management and won't correctly sign out users on the server. This could lead to unintended session issues or affect other users in a multi-user environment.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants