diff --git a/.dockerignore b/.dockerignore index cfabe27..0bd563a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,26 +3,14 @@ # next.js /.next/ -/out/ next-env.d.ts -# production -/build - # misc .DS_Store -# local env files -.env -.env*.local - # typescript *.tsbuildinfo -# site map -public/sitemap.xml -public/robots.txt - # docker Dockerfile* .dockerignore diff --git a/.env.example b/.env.example index 1ec2c58..67a64b3 100644 --- a/.env.example +++ b/.env.example @@ -8,10 +8,11 @@ # When adding additional environment variables, the schema in "/src/env.js" # should be updated accordingly. +# Also update any GitHub Actions that use these variables. # General -NEXT_TELEMETRY_DISABLED="true" NODE_ENV="development" +NEXT_TELEMETRY_DISABLED="true" NEXT_PUBLIC_SITE_URL="http://localhost:3000" # Database diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 2b21c9d..16f4c25 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -23,7 +23,6 @@ jobs: env: NEXT_TELEMETRY_DISABLED: true NODE_ENV: "production" - NEXT_PUBLIC_SITE_URL: "http://localhost:3000" DATABASE_HOST: "localhost" DATABASE_PORT: "5432" DATABASE_USER: "user" @@ -39,6 +38,7 @@ jobs: FEIDE_AUTHORIZATION_ENDPOINT: "https://auth.dataporten.no/oauth/authorization" FEIDE_TOKEN_ENDPOINT: "https://auth.dataporten.no/oauth/token" FEIDE_USERINFO_ENDPOINT: "https://auth.dataporten.no/openid/userinfo" + NEXT_PUBLIC_SITE_URL: "http://localhost:3000" steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/deploy-script.yml b/.github/workflows/deploy-script.yml new file mode 100644 index 0000000..38045f4 --- /dev/null +++ b/.github/workflows/deploy-script.yml @@ -0,0 +1,42 @@ +name: SSH Deploy Script + +on: + workflow_call: + inputs: + environment: + required: true + type: string + branch: + required: true + type: string + path: + required: true + type: string + secrets: + host: + required: true + port: + required: true + key: + required: true + username: + required: true + +jobs: + script: + name: Script + runs-on: ubuntu-latest + environment: ${{ inputs.environment }} + steps: + - uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.host }} + port: ${{ secrets.port }} + key: ${{ secrets.key }} + username: ${{ secrets.username }} + script: | + cd ${{ inputs.path }} + git checkout ${{ inputs.branch }} + git pull + docker compose down + docker compose up --build -d diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..74009b9 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,43 @@ +name: Deploy + +on: + push: + branches: + - main + - dev + workflow_dispatch: + inputs: + environment: + description: 'Deployment environment' + required: true + default: 'Development' + enum: ['Production', 'Development'] + +jobs: + deploy-prod: + name: Production + if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'Production') + uses: ./.github/workflows/deploy-script.yml + with: + environment: Production + branch: main + path: website-next + secrets: + host: ${{ secrets.HOST }} + port: ${{ secrets.PORT }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.KEY }} + + deploy-dev: + name: Development + if: github.ref == 'refs/heads/dev' || (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'Development') + uses: ./.github/workflows/deploy-script.yml + with: + environment: Development + branch: dev + path: website-next + secrets: + host: ${{ secrets.HOST }} + port: ${{ secrets.PORT }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.KEY }} diff --git a/.gitignore b/.gitignore index c55f229..b8a2932 100644 --- a/.gitignore +++ b/.gitignore @@ -3,18 +3,13 @@ # next.js /.next/ -/out/ next-env.d.ts -# production -/build - # misc .DS_Store # local env files .env -.env*.local # typescript *.tsbuildinfo diff --git a/Dockerfile b/Dockerfile index bcd4f37..b16432f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,67 +18,27 @@ COPY --from=deps /app/node_modules ./node_modules COPY . . ENV NODE_ENV=production -ENV NEXT_TELEMETRY_DISABLED=1 ENV SKIP_ENV_VALIDATION=true -# Set environment variables during the build -ARG NEXT_PUBLIC_SITE_URL -ARG DATABASE_USER -ARG DATABASE_PASSWORD -ARG DATABASE_HOST -ARG DATABASE_PORT -ARG DATABASE_NAME -ARG STORAGE_HOST -ARG STORAGE_PORT -ARG STORAGE_USER -ARG STORAGE_PASSWORD -ARG STORAGE_NAME -ARG FEIDE_CLIENT_ID -ARG FEIDE_CLIENT_SECRET -ARG FEIDE_AUTHORIZATION_ENDPOINT -ARG FEIDE_TOKEN_ENDPOINT -ARG FEIDE_USERINFO_ENDPOINT - -ENV NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL -ENV DATABASE_USER=$DATABASE_USER -ENV DATABASE_PASSWORD=$DATABASE_PASSWORD -ENV DATABASE_HOST=$DATABASE_HOST -ENV DATABASE_PORT=$DATABASE_PORT -ENV DATABASE_NAME=$DATABASE_NAME -ENV STORAGE_HOST=$STORAGE_HOST -ENV STORAGE_PORT=$STORAGE_PORT -ENV STORAGE_USER=$STORAGE_USER -ENV STORAGE_PASSWORD=$STORAGE_PASSWORD -ENV STORAGE_NAME=$STORAGE_NAME -ENV FEIDE_CLIENT_ID=$FEIDE_CLIENT_ID -ENV FEIDE_CLIENT_SECRET=$FEIDE_CLIENT_SECRET -ENV FEIDE_AUTHORIZATION_ENDPOINT=$FEIDE_AUTHORIZATION_ENDPOINT -ENV FEIDE_TOKEN_ENDPOINT=$FEIDE_TOKEN_ENDPOINT -ENV FEIDE_USERINFO_ENDPOINT=$FEIDE_USERINFO_ENDPOINT - # Build the application -RUN bunx next build - +RUN bun run build # Production image, copy all the files and run next FROM base AS runner WORKDIR /app ENV NODE_ENV=production -ENV NEXT_TELEMETRY_DISABLED=1 +ENV NEXT_TELEMETRY_DISABLED=true ENV SKIP_ENV_VALIDATION=true RUN addgroup --system --gid 1002 nodejs && \ adduser --system --uid 1002 nextjs -COPY --from=builder /app/public ./public - # Set the correct permission for prerender cache RUN mkdir .next && chown nextjs:nodejs .next # Automatically leverage output traces to reduce image size COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ -COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static USER nextjs diff --git a/README.md b/README.md index ff10aff..ddba536 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Here is a list of documentation to help you get started: - [Next-intl](https://next-intl-docs.vercel.app/) - Internationalization library - [nuqs](https://nuqs.47ng.com/docs/installation) - Easy to use query params - [BlockNote](https://www.blocknotejs.org/docs) - Tool for markdown textboxes -- [Tanstack Form](https://tanstack.com/form/latest/docs/overview) - When we need to handle form validation (shadcn/ui uses react-hook-form. but I think this is better, we will figure it out) +- [React Hook Form](https://react-hook-form.com/get-started) - When we need to handle form validation - [Tanstack Query](https://tanstack.com/query/latest/docs/framework/react/overview) - TRPC wraps Tanstack Query which is how we fetch data from the backend #### Styling @@ -85,7 +85,9 @@ You can build the project with the following command: bun run build ``` -Then to serve the build locally, run: +Then setup environment variables by copying the `.env.example` file to `.env` and fill in the values. `.env` files are used to store sensitive information like API keys and database credentials and it will not be committed to the repository. + +To serve the build locally, run: ```bash bun run start @@ -113,7 +115,7 @@ We are using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0. - To keep the code as consistent as possible use functions for react components or hooks instead of const variables with arrow function syntax. An exception is when using the forwardRef hook or when creating compound components. - Only use default export for pages or layouts etc. since it is required by Next.js. For everything else use named exports. This is to make it easier to find the components in the codebase or change them without ending up with different names for the same component. -- Use `type` instead of `interface` for typescript types. This is to keep the code consistent and to make it easier to read. Aldso `type` is more flexible than `interface` since it can be used for unions and intersections. +- Use `type` instead of `interface` for typescript types. This is to keep the code consistent and to make it easier to read. Also `type` is more flexible than `interface` since it can be used for unions and intersections. ### Naming conventions diff --git a/bun.lockb b/bun.lockb index 878935d..327f808 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/docker-compose.yml b/docker-compose.yml index dae14ff..72d7891 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,25 +5,9 @@ services: build: context: . dockerfile: Dockerfile - args: - - NEXT_PUBLIC_SITE_URL - - DATABASE_HOST - - DATABASE_PORT - - DATABASE_USER - - DATABASE_PASSWORD - - DATABASE_NAME - - STORAGE_HOST - - STORAGE_PORT - - STORAGE_USER - - STORAGE_PASSWORD - - STORAGE_NAME - - FEIDE_CLIENT_ID - - FEIDE_CLIENT_SECRET - - FEIDE_AUTHORIZATION_ENDPOINT - - FEIDE_TOKEN_ENDPOINT - - FEIDE_USERINFO_ENDPOINT ports: - "3000:3000" + restart: unless-stopped db: image: postgres:16 environment: @@ -34,6 +18,7 @@ services: - ./data/db:/var/lib/postgresql/data ports: - "5432:5432" + restart: unless-stopped s3: image: bitnami/minio:2024 environment: @@ -44,3 +29,4 @@ services: - ./data/s3:/bitnami/minio/data ports: - "9000:9000" + restart: unless-stopped diff --git a/package.json b/package.json index b15b270..4b7093b 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,12 @@ "type": "module", "scripts": { "prepare": "if [ \"$NODE_ENV\" != \"production\" ]; then lefthook install; fi", - "postbuild": "next-sitemap", - "prebuild": "next telemetry disable", - "build": "next build", "dev": "next dev --turbo", "lint": "biome check --write", - "start": "next start", + "prebuild": "next telemetry disable", + "build": "next build", + "postbuild": "next-sitemap && mkdir -p .next/standalone/public .next/standalone/.next/static && cp -r public/* .next/standalone/public && cp -r .next/static/* .next/standalone/.next/static", + "start": "bun run .next/standalone/server.js", "db:start": "docker-compose up db", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", @@ -42,7 +42,7 @@ "drizzle-orm": "^0.33.0", "lucia": "^3.2.0", "lucide-react": "^0.396.0", - "next": "^14.2.4", + "next": "^14.2.10", "next-intl": "^3.18.1", "next-sitemap": "^4.2.3", "next-themes": "^0.3.0", diff --git a/src/env.js b/src/env.js index c49682a..0fde631 100644 --- a/src/env.js +++ b/src/env.js @@ -40,7 +40,6 @@ export const env = createEnv({ */ runtimeEnv: { NODE_ENV: process.env.NODE_ENV, - NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL, DATABASE_HOST: process.env.DATABASE_HOST, DATABASE_PORT: process.env.DATABASE_PORT, DATABASE_USER: process.env.DATABASE_USER, @@ -56,6 +55,7 @@ export const env = createEnv({ FEIDE_AUTHORIZATION_ENDPOINT: process.env.FEIDE_AUTHORIZATION_ENDPOINT, FEIDE_TOKEN_ENDPOINT: process.env.FEIDE_TOKEN_ENDPOINT, FEIDE_USERINFO_ENDPOINT: process.env.FEIDE_USERINFO_ENDPOINT, + NEXT_PUBLIC_SITE_URL: process.env.NEXT_PUBLIC_SITE_URL, }, /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially diff --git a/src/lib/api/client.ts b/src/lib/api/client.ts index df56eaf..6e2a341 100644 --- a/src/lib/api/client.ts +++ b/src/lib/api/client.ts @@ -1,4 +1,5 @@ 'use client'; +import 'client-only'; import type { AppRouter } from '@/server/api/root'; import { createTRPCReact } from '@trpc/react-query';