diff --git a/nest-intra/.gitignore b/nest-intra/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/nest-intra/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/nest-intra/Dockerfile b/nest-intra/Dockerfile new file mode 100644 index 0000000..e94f5ce --- /dev/null +++ b/nest-intra/Dockerfile @@ -0,0 +1,18 @@ +FROM node:22-alpine AS build + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +FROM nginx:alpine + +COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 5174 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/nest-intra/README.md b/nest-intra/README.md new file mode 100644 index 0000000..5f2670a --- /dev/null +++ b/nest-intra/README.md @@ -0,0 +1,60 @@ +# CrowMate Intranet + +Internal staff portal for CrowMate Studio — Headless Hazard. + +## Quick Start + +```bash +npm install +npm run dev +``` + +The intranet runs on **http://localhost:5174** (port 5174 to avoid conflicts with the public site on 5173). + +## Demo Accounts + +| Account | Email | Role | +|---------|-------|------| +| Kestrel (Admin) | `kestrel@crowmate.dev` | dev + admin | +| Vesper (Staff) | `vesper@crowmate.dev` | com | + +Regular user accounts are blocked from intranet access. + +## Project Structure + +``` +src/ + App.tsx # Router (login + intranet routes) + main.tsx # Entry point + index.css # Design tokens & global styles + contexts/ + AuthContext.tsx # Auth state (staff-only login) + components/ + layout/ + IntranetLayout.tsx # Sidebar + main content layout + shared/ + ProtectedRoute.tsx # Route guard (auth + staff check) + PageLoader.tsx # Loading spinner + pages/ + LoginPage.tsx # Staff login page + intranet/ + IntranetDashboard.tsx # Overview stats & nav tiles + IntranetBugs.tsx # Bug triage (filter, assign, notes) + IntranetFeed.tsx # Staff-only activity feed + IntranetEvents.tsx # Create/manage events & polls + IntranetUsers.tsx # User management (promote/ban) + IntranetModeration.tsx # Forum moderation (pin/lock/delete) + data/ + mockData.ts # All mock data + types/ + index.ts # TypeScript interfaces + utils/ + format.ts # Date formatting helpers +``` + +## Scripts + +- `npm run dev` — Start dev server +- `npm run build` — Type-check + production build +- `npm run lint` — Run ESLint +- `npm run preview` — Preview production build diff --git a/nest-intra/docker-compose.yml b/nest-intra/docker-compose.yml new file mode 100644 index 0000000..a6bae3f --- /dev/null +++ b/nest-intra/docker-compose.yml @@ -0,0 +1,6 @@ +services: + nest-intra: + build: . + ports: + - "5174:5174" + restart: unless-stopped diff --git a/nest-intra/eslint.config.js b/nest-intra/eslint.config.js new file mode 100644 index 0000000..5e6b472 --- /dev/null +++ b/nest-intra/eslint.config.js @@ -0,0 +1,23 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + js.configs.recommended, + tseslint.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + }, +]) diff --git a/nest-intra/index.html b/nest-intra/index.html new file mode 100644 index 0000000..c908613 --- /dev/null +++ b/nest-intra/index.html @@ -0,0 +1,16 @@ + + +
+ + + + + + ++ Post game development updates, announcements, and community polls. Public events are + visible to all users. +
++ Staff-only internal feed. Posts are not visible to the public. +
++ {threads.length} threads — {replies.length} replies +
+
+ External services and tools. Edit public/services.json to update this list.
+
+ {confirmAction.action === 'promote' + ? `Promote this user to staff? They will gain access to the intranet.` + : confirmAction.action === 'ban' + ? `Ban this user? They will be unable to login.` + : `Unban this user? They will regain access to their account.`} +
+| + {h} + | + ))} +|||||||
|---|---|---|---|---|---|---|---|
| + {u.username} {isSelf && (you)} + | +{u.email} | +
+ |
+ {formatDate(u.createdAt)} | +0 | +0 | ++ {u.isBanned ? ( + Banned + ) : ( + Active + )} + | +
+ {!isSelf && !u.isAdmin && (
+
+ {u.role === 'user' && currentUser?.isAdmin && (
+
+ )}
+ {u.isBanned ? (
+
+ ) : (
+
+ )}
+
+ )}
+ |
+