Skip to content

Commit

Permalink
save progress
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerlepine committed Oct 18, 2024
1 parent c4a6044 commit db5f36b
Show file tree
Hide file tree
Showing 104 changed files with 1,988 additions and 409 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
npm-debug.log
.env
.git
13 changes: 3 additions & 10 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
MY_SECRET_VALUE="foobar"

# Auth0 - https://auth0.com/docs/quickstart/webapp/nextjs/interactive
# Allowed callback URLs: https://my-app.vercel.app/api/auth/callback, http://localhost:3000/api/auth/callback
# Allowed logout URLs: https://my-app.vercel.app, http://localhost:3000
AUTH0_SECRET='use [openssl rand -hex 32] to generate a 32 bytes value'
AUTH0_BASE_URL='http://localhost:3000'
AUTH0_ISSUER_BASE_URL='https://{yourDomain}'
AUTH0_CLIENT_ID='{yourClientId}'
AUTH0_CLIENT_SECRET='{yourClientSecret}'
NEXT_PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_STRIPE_KEY="pk_asdfasdfasdfasdfasdf"
STRIPE_SECRET_KEY="sk_asdfasdfasdfasdfasdf"
60 changes: 60 additions & 0 deletions .github/workflows/bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# bootstrap.sh

#!/bin/bash

# Check if PUBLIC_KEY is set
if [ -z "$PUBLIC_KEY" ]; then
echo "Error: PUBLIC_KEY environment variable is not set."
exit 1
fi

# Check if DOMAIN is set
if [ -z "$DOMAIN" ]; then
echo "Error: DOMAIN environment variable is not set."
exit 1
fi

# Check if EMAIL is set
if [ -z "$EMAIL" ]; then
echo "Error: EMAIL environment variable is not set."
exit 1
fi

# Update and install necessary packages
apt update && apt upgrade -y
apt install -y software-properties-common

# Install Docker
apt install -y docker.io
systemctl enable docker
systemctl start docker

# Install Docker Compose
DOCKER_COMPOSE_VERSION="v2.16.0" # Change to the desired version
curl -SL "https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

# Configure UFW
ufw allow OpenSSH
ufw enable

# Install Certbot and Nginx
apt install -y certbot

# Obtain the SSL certificate using standalone mode
certbot certonly --standalone -d "$DOMAIN" --non-interactive --agree-tos --email "$EMAIL"


# Disable password authentication
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh

# Add SSH public key
mkdir -p ~/.ssh
echo "$PUBLIC_KEY" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

# Restart UFW to apply changes
systemctl restart ufw

echo "Bootstrap script completed successfully."
43 changes: 43 additions & 0 deletions .github/workflows/manual-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# .github/workflows/manual-deploy.yml
# TODO_DEPLOYMENT

name: Manually Deploy

on:
push:
branches:
- main

jobs:
#bootstrap:
# run bootstrap.ssh?
# PUBLIC_KEY="your_ssh_public_key_here" DOMAIN="your_domain_here" bash bootstrap.sh

deploy:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Re-deploy, update secrets
env:
# secure: only stored in memory during the remote-ssh session
API_KEY: ${{ secrets.API_KEY }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
run: |
ssh user@your-vm-ip << 'EOF'
# Authenticate with GitHub CLI using the passed PAT
echo "$GITHUB_TOKEN" | gh auth login --with-token

# Create the .env file with secrets
{
echo "API_KEY=$API_KEY"
echo "DB_PASSWORD=$DB_PASSWORD"
} > .env

# Run docker-compose with the .env file
docker-compose --env-file .env up -d

# Remove the .env file immediately
rm .env
EOF
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.0.2] - 2024-10-14

MVP landing page and product catalog

## [0.0.1] - 2024-09-18

Boilerplate Next.js (App Router) code
Expand Down
9 changes: 9 additions & 0 deletions COMMITS
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(update the changelog each time)
commits:
feat: landing page with dummy data
feat: client-side cart item storage
feat: stripe checkout with dummy data
feat: printify
feat: passwordless email login
feat: enable fully functioning checkout (stripe + printify)
docs: improve README
24 changes: 24 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Build Stage
FROM node:20.16-alpine3.19 AS build

WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production Stage
FROM node:20.16-alpine3.19 AS production

# Use a non-root user for security
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

WORKDIR /usr/src/app
COPY --from=build /usr/src/app ./

# Document the port that may need to be published
EXPOSE 3000

# Start the application
CMD ["npm", "start"]
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Next.js Fullstack DigitalOcean Droplet VM
# SwagSticker.com Demo App

Fullstack Next.js (App Router) deployed to DigitalOcean App Platform
Jamstack ecommerce store. Fullstack Next.js with server-side rendering (App Router, v14)

## Local Development

Expand All @@ -19,7 +19,7 @@ npm install
### Run Locally

```sh
cp .env.template .env.local
cp .env.template .env.development
npm run dev
# visit http://locahost:3000
```
Expand All @@ -28,10 +28,19 @@ npm run dev

```sh
cp .env.template .env.production
NODE_ENV=production npm run build
npm run build
```

### Docker

```
docker-compose --env-file .env up -d
```

## Resources

- Next.js docs: https://nextjs.org/docs/getting-started/installation
- Auth0 walkthrough: https://auth0.com/docs/quickstart/webapp/nextjs/interactive
- Next: Checkout: https://medium.com/@pether.maciejewski/easy-stripe-checkout-with-use-shopping-cart-and-next-js-14-8895c9865437
- Next: Passwordless Auth: https://dev.to/cotter/passwordless-login-with-email-and-json-web-token-jwt-authentication-using-next-js-539o

- More Auth (just to reference): https://medium.com/@kcsanjeeb091/implementing-jwt-based-authentication-with-next-js-v14-and-nextauth-v4-e3efca4b158b
103 changes: 103 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
services:
watchtower:
image: containrrr/watchtower
command:
- "--label-enable"
- "--interval"
- "30"
- "--rolling-restart"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
reverse-proxy:
image: traefik:v3.1
command:
- "--log.level=ERROR"
- "--accesslog=true"
- "--providers.docker"
- "--providers.docker.exposedbydefault=false"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=elliott@zenful.cloud"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entryPoints.web.forwardedHeaders.insecure"
- "--entryPoints.websecure.forwardedHeaders.insecure"
ports:
- "80:80"
- "443:443"
volumes:
- letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock
nextjs-app:
image: ghcr.io/spencerlepine/nextjs-app:prod
labels:
- "traefik.enable=true"
- "traefik.http.middlewares.nextjs-app-ratelimit.ratelimit.average=20"
- "traefik.http.routers.nextjs-app.rule=Host(`zenful.cloud`) && !Method(`POST`)"
- "traefik.http.routers.nextjs-app.entrypoints=websecure"
- "traefik.http.routers.nextjs-app.tls.certresolver=myresolver"
- "traefik.http.routers.nextjs-app.middlewares=nextjs-app-ratelimit"
# Define separate router for POST methods
- "traefik.http.middlewares.nextjs-app-ratelimit-post.ratelimit.average=1"
- "traefik.http.middlewares.nextjs-app-ratelimit-post.ratelimit.period=1m"
- "traefik.http.routers.nextjs-app-post.rule=Host(`zenful.cloud`) && Method(`POST`)"
- "traefik.http.routers.nextjs-app-post.middlewares=nextjs-app-ratelimit-post"
- "traefik.http.routers.nextjs-app-post.entrypoints=websecure"
- "traefik.http.routers.nextjs-app-post.tls.certresolver=myresolver"
# Proxy
- "traefik.http.routers.proxy.rule=Host(`proxy.dreamsofcode.io`)"
- "traefik.http.routers.proxy.entrypoints=websecure"
- "traefik.http.routers.proxy.tls.certresolver=myresolver"
# Enable watchtower
- "com.centurylinklabs.watchtower.enable=true"
environment:
- POSTGRES_HOST=db
- POSTGRES_USER=postgres
- POSTGRES_DB=nextjs-app
- POSTGRES_PORT=5432
- POSTGRES_SSLMODE=disable
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
deploy:
mode: replicated
replicas: 3
restart: always
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres
restart: always
user: postgres
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=nextjs-app
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
expose:
- 5432
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 10s
timeout: 5s
retries: 5

dragonfly:
image: 'docker.dragonflydb.io/dragonflydb/dragonfly'
ulimits:
memlock: -1
network_mode: "host"
volumes:
- dragonflydata:/data

volumes:
db-data:
letsencrypt:
dragonflydata:
22 changes: 7 additions & 15 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'lh3.googleusercontent.com',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 's.gravatar.com',
port: '',
pathname: '/**',
},
],
}
remotePatterns: [{
protocol: 'http',
hostname: 'localhost',
port: '3000',
pathname: '/images/**'
}]
},
};

export default nextConfig;
13 changes: 9 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,18 @@
},
"scripts": {
"dev": "next dev",
"build": "next build",
"build": "NODE_ENV=production next build",
"test": "echo 'No tests added yet' && exit 0",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@auth0/nextjs-auth0": "^3.5.0",
"fuse.js": "^7.0.0",
"next": "14.2.11",
"react": "^18",
"react-dom": "^18"
"react-dom": "^18",
"stripe": "^16.9.0",
"use-shopping-cart": "^3.2.0"
},
"devDependencies": {
"@types/node": "^20",
Expand All @@ -37,7 +39,10 @@
"extends": [
"next/core-web-vitals",
"next/typescript"
]
],
"rules": {
"@typescript-eslint/ban-ts-comment": "warn"
}
},
"prettier": {
"printWidth": 180,
Expand Down
Binary file added public/images/2x2in-sticker-mockup.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/3x3in-sticker-mockup.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/4x4in-sticker-mockup.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/airtable.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/amazon-web-services-hexagon.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/amazon-web-services.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/android.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/ansible.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/azure.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/c-plus-plus.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/c-sharp.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/c.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/chatgpt.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/chrome.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/cloudflare.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/css.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/django.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/docker.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/dot-net-core.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/elasticsearch.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/figma.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/firebase.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/flask.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/git.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/github-head.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/github-octocat.jpg
Binary file added public/images/go-gopher.jpg
Binary file added public/images/graphql.jpg
Binary file added public/images/html.jpg
Binary file added public/images/java.jpg
Binary file added public/images/javascript.jpg
Binary file added public/images/jquery.jpg
Binary file added public/images/kubernetes.jpg
Binary file added public/images/mongo-db-shield.jpg
Binary file added public/images/nodejs.jpg
Binary file added public/images/open-source.jpg
Binary file added public/images/python.jpg
Binary file added public/images/react.jpg
Binary file added public/images/ruby-on-rails.jpg
Binary file added public/images/ruby.jpg
Binary file added public/images/rust.jpg
Binary file added public/images/slack.jpg
Binary file added public/images/stack-overflow.jpg
Binary file added public/images/supabase.jpg
Binary file added public/images/svelte.jpg
Binary file added public/images/tensorflow.jpg
Binary file added public/images/typescript.jpg
Binary file added public/images/ubuntu.jpg
Binary file added public/images/vscode.jpg
Binary file added public/images/webpack.jpg
1 change: 0 additions & 1 deletion public/next.svg
Diff not rendered.
8 changes: 8 additions & 0 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<xml version="1.0" encoding="UTF-8">
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>http://www.swagsticker.com</loc>
<lastmod>2024-10-14</lastmod>
</url>
</urlset>
</xml>
Loading

0 comments on commit db5f36b

Please sign in to comment.