E-Library with Secure PDF Access
Project Overview & Objectives:
The E-Library with Secure PDF Access is a modern, web-based
platform designed to provide users with a seamless and secure
digital reading experience. The core problem it addresses is the
challenge of distributing and accessing digital books (primarily
PDFs) in a controlled manner, preventing unauthorized copying,
redistribution, and ensuring that content is only available to
verified users.
Key features will include:
User Authentication & Authorization:Secure user registration and
login.
* Role-Based Access Control (RBAC):Differentiating between
Admin users (who can upload and manage books) and Members
(who can read books).
* Digital Library Catalog: A searchable and categorized collection
of books with details like title, author, description, and cover
image.
* Secure PDF Viewer:Integrated PDF viewer that prevents easy
downloading and printing. PDFs will be served dynamically rather
than via direct, static links.
* Reading Progress Tracking:Allows users to bookmark their last
read page and resume from there.
* Admin Dashboard: A dedicated interface for admins to upload
new books, manage existing ones, and view user activity.
The expected outcome is a fully functional, secure, and user-
friendly web application that can be deployed by educational
institutions, small libraries, or organizations to manage and share
their digital document collections confidently.
---
Phase 1: Planning & Foundation
1. Technology Stack & Environment Setup
* Backend:
* Runtime:[Link]
* Framework: [Link] for building robust and scalable
RESTful APIs.
* Authentication:JSON Web Tokens (JWT) for stateless and
secure user sessions.
* Password Hashing:bcryptjs to securely hash user passwords
before storing them.
* Database:
* System: MongoDB with Mongoose ODM. Its flexible schema
is ideal for storing book metadata and user profiles. Collections
will include `Users`, `Books`, and `ReadingSessions`.
* Frontend:
* Framework:[Link] (with Vite for fast setup) to create a
dynamic and responsive single-page application (SPA).
* State Management: React Context API or Redux Toolkit for
managing global state like user authentication and the list of
books.
* UI Library:Tailwind CSS for rapid and modern UI development.
* PDF Viewer: Mozilla's `[Link]` integrated into a React
component to display PDFs securely without exposing the original
file URL.
* Tools & Services:
* Version Control:Git with a repository on GitHub.
* Package Manager:npm or yarn.
* File Upload:Multer` middleware for handling PDF and cover
image uploads.
* Deployment: Backend on Render or Railway, Frontend on
Netlify or Vercel, and MongoDB Atlas for the database.
2. API Design & Data Model
Data Models (Schema):
* User: `{ _id, email, passwordHash, role ("admin" / "member"),
createdAt }`
* Book: `{ _id, title, author, description, genre, coverImageUrl,
pdfUrl, uploadDate, uploadedBy (ref to User) }`
* *ReadingSession: `{ _id, userId (ref to User), bookId (ref to
Book), lastPage, updatedAt }`
Planned REST Endpoints:
* Authentication Routes:
* `POST /api/auth/register` - Create a new member account.
* `POST /api/auth/login` - Authenticate user and return a JWT.
* Book Routes (Protected):
* `GET /api/books` - Get a paginated list of all books
(search/filterable).
* `GET /api/books/:id` - Get details of a single book.
* Admin Routes (Protected & Admin-only):
* `POST /api/admin/books` - Upload a new book (cover image
+ PDF).
* `PUT /api/admin/books/:id` - Update book metadata.
* `DELETE /api/admin/books/:id` - Remove a book from the
library.
* Reading Routes (Protected):
* `GET /api/read/:bookId` - Securely serve the PDF file for the
integrated viewer. This endpoint will verify the user's JWT before
streaming the file.
* `POST /api/read/progress` - Save or update the user's
current page in a book.
3. Front-End UI/UX Plan
*Wireframes & Navigation Flow:
1. Public Landing Page: Showcases the library, with calls-to-
action for login and register.
2. *Login/Registration Pages:Simple forms for user access.
3. Member Dashboard:Upon login, users see a searchable grid
of book cards. A navigation bar provides links to the catalog and a
logout button.
4. *Book Detail Page:Clicking a book card opens a page with
the book's description, author, and a "Start Reading" button.
5. Reading Page:A clean, focused interface with the [Link]
viewer. The navigation is minimal, and the browser's right-click
"Save As" functionality will be disabled for the PDF iframe.
6. *Admin Dashboard:A separate view for admins with a form
to upload books and a table to manage existing ones.
* State Management Approach:The React Context API will be
used to create an `AuthContext` to manage the global user state
(user info, JWT token, login status). A `BookContext` may be used
to cache the library catalog for faster navigation.
4. Development & Deployment Plan
* Team Roles:
* Backend Developer:Focuses on [Link]/Express API,
database models, authentication, and secure file delivery.
* Frontend Developer: Implements the React UI, integrates
with the API, and builds the secure PDF viewer component.
* UI/UX Designer (can be shared role):** Creates wireframes
and ensures a consistent design system with Tailwind CSS.
* Git Workflow:
* Use a feature-branch workflow. `main` branch will always
hold the production-ready code.
* New features will be developed in branches named
`feature/description` (e.g., `feature/user-authentication`).
* Pull Requests (PRs) are required to merge a feature branch
into `main`, ensuring code review.
* Testing Approach:
* Backend: Use Jest and Supertest for unit and integration
testing of API endpoints.
* Frontend:Use React Testing Library for component testing.
* Manual Testing:Thoroughly test user flows like registration,
login, book upload, and the secure reading experience.
* Hosting & Deployment Strategy:
1. Database: Set up a production cluster on MongoDB Atlas.
2. Backend:Deploy the [Link]/Express API to Render or
Railway, connecting it to the MongoDB Atlas database.
3. Frontend: Build the React app into static files and deploy
them on Netlify or Vercel. The frontend will be configured to
communicate with the deployed backend API URL.
This comprehensive Phase 1 plan provides a solid blueprint for
developing a robust and secure E-Library, ensuring the team is
aligned on the vision, technology, and execution path before a
single line of code is written.
1. Technology Stack & Data Model Examples
A. Database Schema Examples (MongoDB with Mongoose)
// User Model (models/[Link])
const userSchema = new [Link]({
email: { type: String, required: true, unique: true },
passwordHash: { type: String, required: true },
role: { type: String, enum: ['member', 'admin'], default: 'member' },
createdAt: { type: Date, default: [Link] }
});
// Book Model (models/[Link])
const bookSchema = new [Link]({
title: { type: String, required: true },
author: { type: String, required: true },
description: String,
genre: [String], // e.g., ["Fiction", "Science"]
coverImageUrl: String, // e.g., "/uploads/covers/[Link]"
pdfUrl: { type: String, required: true }, // e.g., "/uploads/pdfs/the-
[Link]"
uploadedBy: { type: [Link], ref: 'User'
},
uploadDate: { type: Date, default: [Link] }
});
// ReadingSession Model (models/[Link])
const readingSessionSchema = new [Link]({
userId: { type: [Link], ref: 'User',
required: true },
bookId: { type: [Link], ref: 'Book',
required: true },
lastPage: { type: Number, default: 1 },
updatedAt: { type: Date, default: [Link] }
});
B. Example JWT Token Payload
When a user logs in, the server creates a JWT token with a
payload like this:
"userId": "507f1f77bcf86cd799439011",
"email": "user@[Link]",
"role": "member",
"iat": 1719500000, // Issued at timestamp
"exp": 1719503600 // Expires in 1 hour
2. API Endpoint Examples
A. User Registration Request & Response
Request:
POST /api/auth/register
Content-Type: application/json
"email": "newuser@[Link]",
"password": "mySecurePassword123"
Success Response (201 Created):
json
"message": "User registered successfully",
"user": {
"id": "507f1f77bcf86cd799439011",
"email": "newuser@[Link]",
"role": "member"
C. Secure PDF Serving Endpoint
Backend Logic (pseudo-code for the route handler)://
routes/[Link]
[Link]('/api/read/:bookId', authenticateUser, async (req, res) => {
try {
const book = await [Link]([Link]);
if (!book) return [Link](404).json({ message: 'Book not
found' });
// Check if user has permission (is logged in)
// The `authenticateUser` middleware already verified the JWT
// Set headers to prevent caching and discourage saving
[Link]('Content-Type', 'application/pdf');
[Link]('Cache-Control', 'no-cache, no-store, must-
revalidate');
[Link]('Pragma', 'no-cache');
// Stream the PDF file to the client
const filePath = [Link](__dirname, '..', [Link]);
const fileStream = [Link](filePath);
[Link](res);
} catch (error) {
[Link](500).json({ message: 'Error serving book' });
});
3. Front-End UI/UX Examples
A. Book Card Component (React)// components/[Link]
import { Link } from 'react-router-dom';
const BookCard = ({ book }) => {
return (
<div className="bg-white rounded-lg shadow-md overflow-
hidden hover:shadow-lg transition-shadow">
<img
src={[Link]}
alt={`Cover of ${[Link]}`}
className="w-full h-48 object-cover"
/>
<div className="p-4">
<h3 className="text-xl font-semibold mb-
2">{[Link]}</h3>
<p className="text-gray-600 mb-2">by {[Link]}</p>
<div className="flex flex-wrap gap-1 mb-3">
{[Link]((tag, index) => (
<span key={index} className="bg-blue-100 text-blue-800
text-xs px-2 py-1 rounded">
{tag}
</span>
))}
</div>
<Link
to={`/book/${book._id}`}
className="bg-blue-500 hover:bg-blue-600 text-white px-4
py-2 rounded block text-center"
>
View Details
</Link>
</div>
</div>
);
};
B. Secure PDF Viewer Component
// components/[Link]
import { useState, useEffect } from 'react';
import { Document, Page, pdfjs } from 'react-pdf';
import 'react-pdf/dist/Page/[Link]';
// Configure [Link] worker
[Link] =
`//[Link]/ajax/libs/[Link]/${[Link]}/[Link]
[Link]`;
const PDFReader = ({ bookId }) => {
const [numPages, setNumPages] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
const [lastSavedPage, setLastSavedPage] = useState(1);
// Secure PDF URL - points to our backend endpoint, not the
direct file
const pdfUrl = `/api/read/${bookId}`;
function onDocumentLoadSuccess({ numPages }) {
setNumPages(numPages);
// Here you would fetch the user's last saved page from the API
// and setPageNumber to that value
// Auto-save progress when page changes
useEffect(() => {
const saveProgress = setTimeout(() => {
if (pageNumber !== lastSavedPage) {
fetch('/api/read/progress', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${[Link]('token')}`
},
body: [Link]({
bookId: bookId,
lastPage: pageNumber
})
});
setLastSavedPage(pageNumber);
}, 1000);
return () => clearTimeout(saveProgress);
}, [pageNumber, bookId, lastSavedPage]);
return (
<div className="pdf-viewer">
<div className="pdf-controls bg-gray-100 p-2 flex justify-
between items-center">
<button
onClick={() => setPageNumber(prev => [Link](prev - 1,
1))}
disabled={pageNumber <= 1}
className="bg-blue-500 text-white px-4 py-2 rounded
disabled:bg-gray-300"
>
Previous
</button>
<span className="text-gray-700">
Page {pageNumber} of {numPages}
</span>
<button
onClick={() => setPageNumber(prev => [Link](prev + 1,
numPages))}
disabled={pageNumber >= numPages}
className="bg-blue-500 text-white px-4 py-2 rounded
disabled:bg-gray-300"
>
Next
</button>
</div>
<div className="pdf-container border">
<Document
file={pdfUrl}
onLoadSuccess={onDocumentLoadSuccess}
options={{
httpHeaders: {
'Authorization': `Bearer ${[Link]('token')}`
}}
>
<Page
pageNumber={pageNumber}
renderTextLayer={false} // Makes text selection harder
/>
</Document>
</div>
</div>
);
};
C. Admin Book Upload Form
// components/[Link]
const AdminUploadForm = () => {
const [formData, setFormData] = useState({
title: '',
author: '',
description: '',
genre: '',
coverImage: null,
pdfFile: null
});
const handleSubmit = async (e) => {
[Link]();
const submitData = new FormData();
[Link]('title', [Link]);
[Link]('author', [Link]);
[Link]('description', [Link]);
[Link]('genre', [Link]);
[Link]('coverImage', [Link]);
[Link]('pdfFile', [Link]);
try {
const response = await fetch('/api/admin/books', {
method: 'POST',
headers: {
'Authorization': `Bearer ${[Link]('token')}`
},
body: submitData
});
if ([Link]) {
alert('Book uploaded successfully!');
// Reset form
setFormData({ title: '', author: '', description: '', genre: '',
coverImage: null, pdfFile: null });
} catch (error) {
alert('Error uploading book');
};
return (
<form onSubmit={handleSubmit} className="space-y-4 max-w
-2xl mx-auto">
<input
type="text"
placeholder="Book Title"
value={[Link]}
onChange={(e) => setFormData({...formData, title:
[Link]})}
className="w-full p-2 border rounded"
required
/>
<input
type="text"
placeholder="Author"
value={[Link]}
onChange={(e) => setFormData({...formData, author:
[Link]})}
className="w-full p-2 border rounded"
required
/>
<textarea
placeholder="Description"
value={[Link]}
onChange={(e) => setFormData({...formData, description:
[Link]})}
className="w-full p-2 border rounded"
rows="3"
/>
<input
type="file"
accept="image/*"
onChange={(e) => setFormData({...formData, coverImage:
[Link][0]})}
className="w-full p-2 border rounded"
required
/>
<input
type="file"
accept=".pdf"
onChange={(e) => setFormData({...formData, pdfFile:
[Link][0]})}
className="w-full p-2 border rounded"
required
/>
<button
type="submit"
className="bg-green-500 text-white px-6 py-2 rounded
hover:bg-green-600"
>
Upload Book
</button>
</form>
);
};