diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dc157ff --- /dev/null +++ b/.dockerignore @@ -0,0 +1,34 @@ +# Include any files or directories that you don't want to be copied to your +# container here (e.g., local build artifacts, temporary files, etc.). +# +# For more help, visit the .dockerignore file reference guide at +# https://docs.docker.com/go/build-context-dockerignore/ + +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.next +**/.cache +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/charts +**/docker-compose* +**/compose.y*ml +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +**/build +**/dist +LICENSE +README.md diff --git a/.gitignore b/.gitignore index dd146b5..5adb050 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ next-env.d.ts # Sentry Config File .env.sentry-build-plugin + +mongodb_data/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a904fd2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM node:18-alpine + +WORKDIR /app + +# Copy package files first to leverage Docker cache +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the app +COPY . . + +# Set environment variables +ENV PORT=3000 +ENV HOST=0.0.0.0 +ENV NODE_ENV=development + +# Expose the port +EXPOSE 3000 + +# Start Next.js in development mode +CMD ["npm", "run", "dev"] diff --git a/README.Docker.md b/README.Docker.md new file mode 100644 index 0000000..fa3048f --- /dev/null +++ b/README.Docker.md @@ -0,0 +1,22 @@ +### Building and running your application + +When you're ready, start your application by running: +`docker compose up --build`. + +Your application will be available at http://localhost:3000. + +### Deploying your application to the cloud + +First, build your image, e.g.: `docker build -t myapp .`. +If your cloud uses a different CPU architecture than your development +machine (e.g., you are on a Mac M1 and your cloud provider is amd64), +you'll want to build the image for that platform, e.g.: +`docker build --platform=linux/amd64 -t myapp .`. + +Then, push it to your registry, e.g. `docker push myregistry.com/myapp`. + +Consult Docker's [getting started](https://docs.docker.com/go/get-started-sharing/) +docs for more detail on building and pushing. + +### References +* [Docker's Node.js guide](https://docs.docker.com/language/nodejs/) \ No newline at end of file diff --git a/README.md b/README.md index e44ad9d..0a236bc 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,23 @@ # Subscribely
- + [![Subscribely Logo](https://i.imgur.com/hicXmxC.png)](https://subscribely-subscription-manager.vercel.app/)
- + [![Next.js](https://img.shields.io/badge/Next.js-15.2.3-black?style=flat-plastic&logo=next.js)](https://nextjs.org/) [![MongoDB](https://img.shields.io/badge/MongoDB-8.12-green?style=flat-plastic&logo=mongodb)](https://www.mongodb.com/) [![Vercel](https://img.shields.io/badge/Deployed_on-Vercel-black?style=flat-plastic&logo=vercel)](https://vercel.com) +[![Docker](https://img.shields.io/badge/Docker-Ready-blue?style=flat-plastic&logo=docker)](https://www.docker.com/) [![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-plastic)](LICENSE)
## 📄 Overview + Subscribely is a creative project built to demonstrate a modern subscription management platform. This project has been in development for 2 months and serves as a showcase for implementing a comprehensive subscription system with role-based access controls. **Note:** This is not a real-world application solving an actual business problem, but rather a creative project demonstrating various technical implementations and solutions. @@ -27,18 +29,19 @@ Subscribely is a creative project built to demonstrate a modern subscription man ## ✨ Showcase | ![Image 1](https://github.com/user-attachments/assets/9e557f57-79a8-4ea7-9918-1b8cd3177d71) | ![Image 2](https://github.com/user-attachments/assets/f8aec892-249c-4561-9019-58116fd76c16) | -|--------------------------------|--------------------------------| +| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | | ![Image 3](https://github.com/user-attachments/assets/6623ef73-e7e2-4f1f-a247-2500cf7ffbe8) | ![Image 4](https://github.com/user-attachments/assets/5bf05861-b21a-430d-bdd0-d2894664aa58) | - ## 🔧 Features ### Authentication + - User registration and login system - Role-based access control (Admin and User roles) - Secure authentication with JWT ### User Features + - Default balance in USD for new accounts - Subscription marketplace ("Subscription Store") - Active subscription management (up to 3 active subscriptions) @@ -46,12 +49,14 @@ Subscribely is a creative project built to demonstrate a modern subscription man - Profile settings with account deletion option ### Admin Features + - Create, edit, and delete subscription packages - View all user subscriptions across the platform - Ability to revoke user subscriptions with automatic email notification - Modify user account balances ### Subscription System + - Configurable subscription packages (name, description, price, status) - Customizable subscription durations (1 day, 14 days, 1 month, etc.) - Automatic balance deduction on purchase @@ -61,6 +66,7 @@ Subscribely is a creative project built to demonstrate a modern subscription man - Admin-initiated subscription revocation ## 📐 Tech Stack + - **Framework**: Next.js 15 with TypeScript - **Styling**: Tailwind CSS - **Database**: MongoDB with Mongoose @@ -71,8 +77,10 @@ Subscribely is a creative project built to demonstrate a modern subscription man - **Monitoring**: Sentry - **Security**: Arcjet - **Deployment**: Vercel +- **Containerization**: Docker and Docker Compose ## 🗂️ Project Structure + The project follows a standard Next.js App Router structure with server actions and API routes. ``` @@ -93,6 +101,8 @@ The project follows a standard Next.js App Router structure with server actions ├── .gitignore ├── .prettierrc.json ├── components.json +├── docker-compose.yml +├── Dockerfile ├── eslint.config.mjs ├── instrumentation-client.ts ├── instrumentation.ts @@ -109,6 +119,7 @@ The project follows a standard Next.js App Router structure with server actions ``` ## 🌐 Development Practices + - Strongly typed with TypeScript - Conventional commits for clear version history - Git workflow configured with Husky and lint-staged @@ -117,6 +128,8 @@ The project follows a standard Next.js App Router structure with server actions ## 📥 Installation +### Standard Installation + ```bash # Clone the repository git clone https://github.com/dan0dev/Subscribely.Subscription.Manager.git @@ -128,7 +141,34 @@ npm install npm run dev ``` +### Docker Installation + +The application can also be run using Docker and Docker Compose, which sets up both the application and MongoDB database in containers with automatic file watching for development. + +#### Prerequisites + +- [Docker](https://www.docker.com/get-started) (20.10.0 or higher) +- [Docker Compose](https://docs.docker.com/compose/install/) (v2.0.0 or higher) + +```bash +# Clone the repository +git clone https://github.com/dan0dev/Subscribely.Subscription.Manager.git + +# Navigate to the project directory +cd Subscribely.Subscription.Manager + +# Create .env file with your environment variables (see Environment Variables section) +# Then start the application with Docker Compose +docker compose up --build + +# For development with live file watching +docker compose up +``` + +The application will be available at `http://localhost:3000`. Any changes made to the source files will be automatically synchronized to the container through the volume mounts and hot-reloading will be triggered by Next.js. + ## 🌳 Environment Variables + Modify the `.env.local` file with your own variables data with the following: ``` @@ -145,9 +185,11 @@ SENTRY_AUTH_TOKEN= ``` ## 💻 Deployment + The application is deployed on Vercel. ## 📝 Todo + - Creating test role as account - Implement automatic subscription expiration (currently subscriptions don't expire automatically) - Add subscription renewal options @@ -160,7 +202,6 @@ Subscribely is an open-source project, and we welcome contributions of all kinds We use [GitHub Issues](https://github.com/dan0dev/Subscribely.Subscription.Manager/issues) for tracking bugs and feature requests. - ## 📃 License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..dfa319c --- /dev/null +++ b/compose.yaml @@ -0,0 +1,39 @@ +version: "3.8" + +services: + frontend: + build: + context: . + dockerfile: Dockerfile + container_name: subscribely + ports: + - "3000:3000" + develop: + watch: + - path: ./package.json + action: rebuild + - path: ./next.config.js + action: rebuild + - path: ./package-lock.json + action: rebuild + - path: . + target: /app + action: sync + environment: + - NODE_ENV=development + - PORT=3000 + - HOST=0.0.0.0 + - MONGODB_URI=${MONGODB_URI} + - JWT_SECRET=${JWT_SECRET} + - JWT_EXPIRES_IN=${JWT_EXPIRES_IN} + - GMAIL_USER=${GMAIL_USER} + - GMAIL_PASSWORD=${GMAIL_PASSWORD} + - ARCJET_KEY=${ARCJET_KEY} + - SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN} + volumes: + - .:/app + - /app/node_modules + - /app/.next + restart: unless-stopped + tty: true + stdin_open: true diff --git a/next.config.ts b/next.config.ts index 0e6dfc0..aaa6e73 100644 --- a/next.config.ts +++ b/next.config.ts @@ -41,7 +41,13 @@ const getCspHeader = () => { // API and WebSocket connections "connect-src": [ "'self'", - // Sentry error reporting (update with your actual Sentry DSN) + // Docker development additions + "http://localhost:*", + "http://127.0.0.1:*", + "http://0.0.0.0:*", + "ws://localhost:*", + "ws://0.0.0.0:*", + // Sentry error reporting "https://o4509210060587008.ingest.de.sentry.io", // Arcjet security service "https://api.arcjet.com", @@ -111,6 +117,21 @@ const nextConfig = { ]; }, + // Explicitly set server configuration + server: { + port: 3000, + hostname: "0.0.0.0", + }, + + // Required for webpack watcher in Docker + webpack: (config: import("webpack").Configuration): import("webpack").Configuration => { + config.watchOptions = { + poll: 1000, + aggregateTimeout: 300, + }; + return config; + }, + // HTTP headers for all responses async headers() { return [ diff --git a/package.json b/package.json index 4552b4f..107970e 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev --turbopack", + "dev": "next dev --hostname 0.0.0.0 --port 3000", "build": "next build", - "start": "next start", + "start": "next start --hostname 0.0.0.0 --port 3000", "lint": "next lint", "prepare": "husky" },