JavedanDrive is a full-stack personal cloud storage application built with Node.js and Express. It provides authenticated users with a Drive-style workspace for organizing folders and managing uploaded files.
The application uses PostgreSQL through Supabase for persistent application data and Supabase Storage for uploaded files. Prisma is used as the database ORM, while EJS provides server-rendered views. Client-side JavaScript adds AJAX-based dashboard navigation and actions without requiring a complete page reload for normal workspace operations.
- Local username/password authentication
- Google OAuth authentication
- GitHub OAuth authentication
- Session-based authentication with Passport
- Folder creation, renaming, navigation, and deletion
- Nested folder hierarchy
- File uploads
- File downloads
- File viewing
- File renaming and deletion
- Root-level file uploads
- AJAX dashboard navigation and actions
- Server-side request validation
- Responsive dark dashboard interface
- Supabase PostgreSQL database
- Supabase Storage for uploaded files
- Prisma database migrations
- Node.js
- Express
- Passport.js
- express-session
- EJS
- express-validator
- method-override
- Prisma ORM
- Supabase PostgreSQL
- Supabase Storage
- Prisma Client
- EJS templates
- Vanilla JavaScript
- CSS
- Space Grotesk
- Render Web Service
- Supabase for PostgreSQL and Storage
The dashboard uses AJAX requests for navigation and workspace operations. The server continues to render the dashboard through EJS, while the client replaces dashboard content without requiring a complete browser page reload.
Install or create the following before running the project:
- Node.js
- npm
- A Supabase project
- A Supabase Storage bucket
- Google OAuth credentials if Google login is enabled
- GitHub OAuth credentials if GitHub login is enabled
JavedanDrive uses Supabase for two separate responsibilities:
- PostgreSQL database
- Object/file storage
Create a Supabase project and wait until the PostgreSQL database is available.
The project uses Prisma with PostgreSQL:
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}DATABASE_URL should contain the database connection string used by Prisma.
DIRECT_URL should contain the direct PostgreSQL connection string used for Prisma operations such as migrations when required by the deployment setup.
Use the connection strings provided by Supabase rather than hard-coding database credentials in the repository.
Create a Storage bucket for uploaded files.
Configure:
SUPABASE_URL=
SUPABASE_PUBLISHABLE_KEY=
SUPABASE_SERVICE_ROLE_KEY=
SUPABASE_BUCKET=
SUPABASE_BUCKET must match the bucket used by the application.
The service-role key is a privileged server-side credential. It must never be exposed to browser-side JavaScript or committed to Git.
Create a .env file in the project root for local development.
Example:
DATABASE_URL="your-supabase-database-url"
DIRECT_URL="your-supabase-direct-database-url"
SECRET="your-session-secret"
SUPABASE_URL="your-supabase-project-url"
SUPABASE_PUBLISHABLE_KEY="your-supabase-publishable-key"
SUPABASE_SERVICE_ROLE_KEY="your-supabase-service-role-key"
SUPABASE_BUCKET="your-storage-bucket-name"
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
GITHUB_CLIENT_ID="your-github-client-id"
GITHUB_CLIENT_SECRET="your-github-client-secret"
NODE_ENV="development"If SESSION_SECRET exists in your environment configuration, keep it only if it is referenced elsewhere in the application. The Express session configuration currently uses SECRET.
Never commit .env to source control.
A typical .gitignore should contain:
node_modules/
.env
.env.*
!.env.exampleClone the repository:
git clone <repository-url>
cd <project-directory>Install dependencies:
npm installGenerate the Prisma Client:
npx prisma generateApply existing migrations:
npx prisma migrate deployDuring development, create new migrations with:
npx prisma migrate devStart the application:
node app.jsThe application should be available at:
http://localhost:3000
The OAuth providers must point to the application's callback routes.
For local development:
Authorized JavaScript origin:
http://localhost:3000
Authorized redirect URI:
http://localhost:3000/auth/google/callback
For production:
Authorized JavaScript origin:
https://your-production-domain.com
Authorized redirect URI:
https://your-production-domain.com/auth/google/callback
For local development:
Homepage URL:
http://localhost:3000
Authorization callback URL:
http://localhost:3000/auth/github/callback
For production:
Homepage URL:
https://your-production-domain.com
Authorization callback URL:
https://your-production-domain.com/auth/github/callback
The callback URLs configured with Google and GitHub must match the callback URLs used by Passport.
The main database models are:
User
Folder
File
Session
Folders support a self-referencing hierarchy:
Folder
|
+-- children
|
+-- children
|
+-- ...
Files can optionally belong to a folder.
Folder deletion uses cascading database relations so that deleting a folder also removes its nested folders and associated file records instead of moving files into the root directory.
File metadata is stored in PostgreSQL while uploaded file objects are stored in Supabase Storage.
Database metadata includes information such as:
- Original filename
- Display filename
- MIME type
- File size
- Owner
- Folder
- Storage path
- Optional URL
This separates application metadata from the actual stored file objects.
The following values are server-side secrets and must never be exposed publicly:
SECRET
DATABASE_URL
DIRECT_URL
SUPABASE_SERVICE_ROLE_KEY
GOOGLE_CLIENT_SECRET
GITHUB_CLIENT_SECRET
Do not expose these values in EJS templates, client-side JavaScript, public files, or Git repositories.
Authentication-protected routes verify the current Passport session before allowing users to access private dashboard resources.
File and folder operations validate ownership before performing database operations.
JavedanDrive can be deployed as a Render Web Service while continuing to use Supabase for PostgreSQL and Storage.
For a repository whose application is located at the repository root:
Root Directory:
leave empty
Build command:
npm install && npx prisma generatePre-Deploy command:
npx prisma migrate deployStart command:
node app.jsSet:
NODE_ENV=production
Configure the following in Render:
DATABASE_URL
DIRECT_URL
SECRET
SUPABASE_URL
SUPABASE_PUBLISHABLE_KEY
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_BUCKET
GOOGLE_CLIENT_ID
GOOGLE_CLIENT_SECRET
GITHUB_CLIENT_ID
GITHUB_CLIENT_SECRET
NODE_ENV
Do not commit production credentials to the repository.
Before deploying:
-
.envis excluded from Git - Supabase database is configured
- Supabase Storage bucket exists
-
DATABASE_URLis correct -
DIRECT_URLis correct - Supabase storage credentials are configured
- Prisma Client can be generated
- Prisma migrations are committed
- Google OAuth callback URL is configured
- GitHub OAuth callback URL is configured
- Production OAuth credentials are available in Render
-
NODE_ENVis set toproduction - The application starts with
node app.js
The dashboard is server-rendered and uses vanilla JavaScript for progressive enhancement.
Normal navigation and workspace actions use AJAX where appropriate. This keeps the interface responsive while preserving the Express and EJS architecture.
The project does not require a frontend framework such as React or Vue.
This project is currently intended as a personal/project application. Add a formal license if the repository will be distributed or reused publicly.