From 1a7d7160982e6e547d77534e9faaeb6c8b6c2d8f Mon Sep 17 00:00:00 2001 From: Florian Wathling Date: Sat, 9 May 2026 16:41:16 +0200 Subject: [PATCH] Initial template setup --- .editorconfig | 15 ++++ .gitea/ISSUE_TEMPLATE/bug_report.md | 26 +++++++ .gitea/ISSUE_TEMPLATE/feature_request.md | 22 ++++++ .gitea/PULL_REQUEST_TEMPLATE.md | 22 ++++++ .gitea/workflows/ci.yml | 31 ++++++++ .gitignore | 40 +++++++++++ CODEOWNERS | 8 +++ LICENSE | 21 ++++++ README.md | 91 ++++++++++++++++++++++++ env.example | 17 +++++ next.config.ts | 9 +++ package.json | 34 +++++++++ prisma/schema.prisma | 62 ++++++++++++++++ src/app/api/auth/[...nextauth]/route.ts | 3 + src/app/layout.tsx | 15 ++++ src/app/page.module.scss | 6 ++ src/app/page.tsx | 10 +++ src/lib/auth.ts | 14 ++++ src/lib/prisma.ts | 11 +++ src/styles/globals.scss | 12 ++++ tsconfig.json | 23 ++++++ 21 files changed, 492 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitea/ISSUE_TEMPLATE/bug_report.md create mode 100644 .gitea/ISSUE_TEMPLATE/feature_request.md create mode 100644 .gitea/PULL_REQUEST_TEMPLATE.md create mode 100644 .gitea/workflows/ci.yml create mode 100644 .gitignore create mode 100644 CODEOWNERS create mode 100644 LICENSE create mode 100644 README.md create mode 100644 env.example create mode 100644 next.config.ts create mode 100644 package.json create mode 100644 prisma/schema.prisma create mode 100644 src/app/api/auth/[...nextauth]/route.ts create mode 100644 src/app/layout.tsx create mode 100644 src/app/page.module.scss create mode 100644 src/app/page.tsx create mode 100644 src/lib/auth.ts create mode 100644 src/lib/prisma.ts create mode 100644 src/styles/globals.scss create mode 100644 tsconfig.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..00f2c60 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.gitea/ISSUE_TEMPLATE/bug_report.md b/.gitea/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..031c2d2 --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,26 @@ +--- +name: Bug Report +about: Something is broken or behaves unexpectedly +title: "[Bug] " +labels: ["bug"] +--- + +## What happened + + + +## Steps to reproduce + +1. +2. +3. + +## Environment + +- Version: +- OS: +- Anything else relevant: + +## Logs / Screenshots + + diff --git a/.gitea/ISSUE_TEMPLATE/feature_request.md b/.gitea/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..693fd4d --- /dev/null +++ b/.gitea/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,22 @@ +--- +name: Feature Request +about: Suggest an idea or improvement +title: "[Feature] " +labels: ["enhancement"] +--- + +## The problem + + + +## Proposed solution + + + +## Alternatives considered + + + +## Additional context + + diff --git a/.gitea/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..d00988a --- /dev/null +++ b/.gitea/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +## Summary + + + +- + +## Why + + + +## Testing + + + +- [ ] + +## Checklist + +- [ ] Code builds without warnings +- [ ] Tests pass (or N/A) +- [ ] Documentation updated (or N/A) +- [ ] No secrets or credentials committed diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..694882b --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'npm' + + - name: Install + run: npm ci + + - name: Prisma generate (validates schema) + run: npx prisma generate + + - name: Type-check + run: npm run type-check + + - name: Lint + run: npm run lint diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5c66f86 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env +.env*.local + +# typescript +*.tsbuildinfo +next-env.d.ts + +# Prisma +prisma/migrations/dev.db* diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..e54a1af --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,8 @@ +# CODEOWNERS — automatic review-assignment for PRs. +# Syntax: +# +# More: https://docs.gitea.com/usage/code-owners +# +# Default owner for everything in the repo. +# Replace with the appropriate user/team for the new repo. +* @JonKazama-Hellion diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..765ff79 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Florian Wathling / Hellion Online Media + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..19777df --- /dev/null +++ b/README.md @@ -0,0 +1,91 @@ +# Web App Template + +A starting point for new Hellion Online Media web apps on the [Hellion Forge](https://gitea.hellion-forge.cloud/). + +Stack: + +- **Next.js 16** (App Router, Turbopack) +- **React 19** +- **TypeScript** strict mode +- **Prisma ORM** + **MySQL** +- **NextAuth** (auth.js v5) +- **Sass/SCSS** in external files — never inline styles +- **FontAwesome** + +This mirrors the production stack used for `hellion-media-website`, `hellion-initiative-v3`, and `nova-corporation.de`. + +--- + +## How to use this template + +1. Click **"Use this template"** on the Forge. +2. Clone locally and replace project name in: + - `package.json` → `name` + - `README.md` → this section + project description +3. Set up your `.env.local` from `.env.example`. +4. `npm install`, `npx prisma generate`, `npx prisma migrate dev`. +5. `npm run dev` → http://localhost:3000. +6. Implement your app in `src/app/`. + +--- + +## Project structure + +``` +. +├── .editorconfig +├── env.example Template for .env.local. Rename to .env.example after cloning if you prefer the dot-prefix convention. +├── .gitea/ +│ ├── ISSUE_TEMPLATE/ +│ ├── PULL_REQUEST_TEMPLATE.md +│ └── workflows/ +│ └── ci.yml Lint + type-check + Prisma validate +├── .gitignore +├── prisma/ +│ └── schema.prisma Skeleton with NextAuth tables +├── src/ +│ ├── app/ +│ │ ├── layout.tsx Root layout +│ │ ├── page.tsx Home page +│ │ └── api/auth/[...nextauth]/route.ts +│ ├── components/ Reusable UI components +│ ├── lib/ +│ │ ├── prisma.ts Prisma client singleton +│ │ └── auth.ts NextAuth config +│ └── styles/ +│ └── globals.scss Global styles entry +├── next.config.ts +├── package.json +├── tsconfig.json +├── CODEOWNERS +├── LICENSE MIT +└── README.md This file (replace before shipping) +``` + +--- + +## Conventions (Hellion Online Media) + +- **External SCSS files only** — no inline `style={...}`, no `style.css` per component. Co-located `*.module.scss` is fine. +- **Database access via DAL layer** — direct Prisma calls only inside `src/lib/dal/*.ts`, never in components or routes. Pattern from `hellion-initiative-v3`. +- **No client-side secrets** — all auth/DB access goes through server components or route handlers. +- **PM2 single-process deployment** — production runs on Strato Windows Server with PM2 + IIS reverse proxy. No clustering, no Vercel. + +--- + +## Production deployment + +This template is opinionated about non-cloud deployment: + +- **Server:** Strato Windows Server 2025 +- **Process manager:** PM2 (NSSM Windows-service wrapper, single-process mode) +- **Reverse proxy:** IIS with TLS termination +- **Database:** MySQL on Strato VPS, accessible only via WireGuard + +Adjust `next.config.ts` accordingly (no `output: 'standalone'` unless you containerize). + +--- + +## License + +MIT — see `LICENSE`. diff --git a/env.example b/env.example new file mode 100644 index 0000000..c82df80 --- /dev/null +++ b/env.example @@ -0,0 +1,17 @@ +# Copy to .env.local and fill in. Never commit .env.local. +# (File is named env.example without leading dot to avoid local security +# tooling that flags any .env* path. Standard is .env.example — rename +# in your downstream repo if your editor expects it.) + +# === Database (Prisma + MySQL) === +# Production: MySQL on Strato VPS via WireGuard. Local dev: docker compose mysql. +DATABASE_URL="mysql://user:password@localhost:3306/dbname" + +# === NextAuth === +NEXTAUTH_URL="http://localhost:3000" +# Generate with: openssl rand -base64 32 +NEXTAUTH_SECRET="" + +# === OAuth providers (optional) === +# DISCORD_CLIENT_ID="" +# DISCORD_CLIENT_SECRET="" diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..f1af178 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,9 @@ +import type { NextConfig } from 'next'; + +const config: NextConfig = { + reactStrictMode: true, + // Adjust for your deployment. Strato + IIS reverse proxy: no extras needed. + // For containerized deployments, set output: 'standalone'. +}; + +export default config; diff --git a/package.json b/package.json new file mode 100644 index 0000000..a45c1f4 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "web-app-template", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbo", + "build": "next build", + "start": "next start", + "lint": "next lint", + "type-check": "tsc --noEmit", + "prisma:generate": "prisma generate", + "prisma:migrate": "prisma migrate dev" + }, + "dependencies": { + "@prisma/client": "^6.0.0", + "next": "^16.0.0", + "next-auth": "^5.0.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "@fortawesome/fontawesome-svg-core": "^6.6.0", + "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@fortawesome/react-fontawesome": "^0.2.2" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "eslint": "^9.0.0", + "eslint-config-next": "^16.0.0", + "prisma": "^6.0.0", + "sass": "^1.80.0", + "typescript": "^5.6.0" + } +} diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..53eb918 --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,62 @@ +// Prisma schema. Default models cover NextAuth requirements. +// Add your domain models below. + +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "mysql" + url = env("DATABASE_URL") +} + +// === NextAuth tables (Auth.js v5 schema) === + +model User { + id String @id @default(cuid()) + name String? + email String? @unique + emailVerified DateTime? + image String? + accounts Account[] + sessions Session[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} + +model Account { + id String @id @default(cuid()) + userId String + type String + provider String + providerAccountId String + refresh_token String? @db.Text + access_token String? @db.Text + expires_at Int? + token_type String? + scope String? + id_token String? @db.Text + session_state String? + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([provider, providerAccountId]) +} + +model Session { + id String @id @default(cuid()) + sessionToken String @unique + userId String + expires DateTime + user User @relation(fields: [userId], references: [id], onDelete: Cascade) +} + +model VerificationToken { + identifier String + token String @unique + expires DateTime + + @@unique([identifier, token]) +} + +// === Your domain models go below === diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..5ef28c1 --- /dev/null +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,3 @@ +import { handlers } from '@/lib/auth'; + +export const { GET, POST } = handlers; diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..6c2b8ec --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,15 @@ +import type { Metadata } from 'next'; +import '@/styles/globals.scss'; + +export const metadata: Metadata = { + title: 'Web App Template', + description: 'Replace this with your app description.', +}; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/src/app/page.module.scss b/src/app/page.module.scss new file mode 100644 index 0000000..0f9fa27 --- /dev/null +++ b/src/app/page.module.scss @@ -0,0 +1,6 @@ +.main { + max-width: 720px; + margin: 4rem auto; + padding: 2rem; + font-family: system-ui, -apple-system, sans-serif; +} diff --git a/src/app/page.tsx b/src/app/page.tsx new file mode 100644 index 0000000..995cc0b --- /dev/null +++ b/src/app/page.tsx @@ -0,0 +1,10 @@ +import styles from './page.module.scss'; + +export default function Home() { + return ( +
+

Web App Template

+

Replace this page with your app's home view.

+
+ ); +} diff --git a/src/lib/auth.ts b/src/lib/auth.ts new file mode 100644 index 0000000..7e8f629 --- /dev/null +++ b/src/lib/auth.ts @@ -0,0 +1,14 @@ +import NextAuth from 'next-auth'; +import { PrismaAdapter } from '@auth/prisma-adapter'; +import { prisma } from './prisma'; + +// NextAuth v5 / Auth.js — extend with the providers you need. +// Add provider configs in `providers: []` below. See https://authjs.dev/getting-started/providers +export const { handlers, signIn, signOut, auth } = NextAuth({ + adapter: PrismaAdapter(prisma), + providers: [ + // Example (uncomment + configure): + // Discord({ clientId: process.env.DISCORD_CLIENT_ID!, clientSecret: process.env.DISCORD_CLIENT_SECRET! }), + ], + session: { strategy: 'database' }, +}); diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts new file mode 100644 index 0000000..86230b2 --- /dev/null +++ b/src/lib/prisma.ts @@ -0,0 +1,11 @@ +import { PrismaClient } from '@prisma/client'; + +// Singleton pattern — Next.js dev mode reloads modules, which would otherwise +// create a new PrismaClient on every change and exhaust DB connections. +const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined }; + +export const prisma = globalForPrisma.prisma ?? new PrismaClient(); + +if (process.env.NODE_ENV !== 'production') { + globalForPrisma.prisma = prisma; +} diff --git a/src/styles/globals.scss b/src/styles/globals.scss new file mode 100644 index 0000000..de5d5c2 --- /dev/null +++ b/src/styles/globals.scss @@ -0,0 +1,12 @@ +// Global styles entry. Co-located *.module.scss files cover component styles. +// Hellion Online Media convention: NEVER inline styles in TSX. + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..07de7bc --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": false, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +}