AntiRecurso is the web frontend for NEI ISEP's exam-preparation platform. It gives students a browser-based interface to practice subject-specific exams, review results, track rankings, browse study notes, and access profile and admin features through a hosted authentication flow.
- Subject-based exam practice with multiple answering modes
- Scoreboards and personal score tracking
- Protected notes area for authenticated users
- Hosted authentication flow backed by NextAuth and Zitadel/AuthNEI
- Admin dashboard for activity, comments, reports, notes, and users
- Cookie consent, changelog popup, theming, and responsive UI
- Runtime: Node.js 20.9+ and pnpm 9
- Framework: Next.js 16 App Router
- UI: React 19, Tailwind CSS, Framer Motion
- Auth: NextAuth 4 with the Zitadel provider
- Validation: Zod
- Charts: Chart.js and react-chartjs-2
- Data Fetching: native
fetchplus SWR where needed - Language: TypeScript
This repository is a frontend application, not the full AntiRecurso platform.
- The UI is rendered by Next.js in
src/app. - Authentication is handled through NextAuth in
src/lib/auth.tswith a hosted Zitadel/AuthNEI login flow. - Business data such as users, subjects, exams, scores, notes, and admin stats comes from an external backend API defined by
NEXT_PUBLIC_BASE_URL. - Authenticated requests can be proxied through
src/app/api/backend/[...path]/route.ts, which forwards the logged-in user's access token to the upstream backend. - Admin routes are guarded by
src/proxy.ts, which checks the session token and validates backend admin access before allowing the request through.
/- landing page/exams- subject picker for exam sessions/exams/[id]/answer- exam answering flow/exams/[id]/review- answer review flow/scoreboard- subject picker for rankings/notes- subject picker for study notes/profile- authenticated user profile and previous results/admin- protected admin dashboard/login,/register,/reset-password- hosted auth entry points
This codebase no longer supports password-based local auth forms.
POST /api/auth/loginPOST /api/auth/registerPOST /api/auth/reset-passwordPOST /api/auth/reset-password/send
These endpoints intentionally return 410 Gone and direct users to the hosted AuthNEI flow instead.
.
βββ assets/ Legacy README screenshots and static media
βββ public/ Favicons, logos, images, manifest, robots.txt
βββ scripts/ Utility scripts
βββ src/
β βββ app/ App Router pages, layouts, route handlers
β βββ components/ UI components by domain
β βββ config/ App constants and feature flags
β βββ contexts/ React context providers
β βββ hooks/ Custom React hooks
β βββ lib/ Auth and server-side session helpers
β βββ schemas/ Zod schemas
β βββ services/ Backend-facing service functions
β βββ styles/ Global and shared styles
β βββ types/ TypeScript domain types
β βββ utils/ Shared helpers
βββ .env.example Sample environment configuration
βββ next.config.js Next.js configuration
βββ package.json Scripts and dependencies
βββ tailwind.config.js Tailwind setup
Install the following before running the project locally:
- Node.js
>=20.9.0 - pnpm
>=9 - Access to a running AntiRecurso backend API
- Access to a Zitadel/AuthNEI client configuration for local login testing
If you use nvm, the repository includes .nvmrc.
git clone <your-fork-or-origin-url>
cd antirecursonvm useIf you do not use nvm, install a compatible Node.js version manually.
The project enforces pnpm via only-allow.
pnpm installCopy the example file:
cp .env.example .env.localNext.js also works with .env, but .env.local is the preferred local-development file.
At minimum, define the variables below before starting the app.
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_BASE_URL |
Yes | Base URL of the AntiRecurso backend API. This is required by the frontend code but is not currently present in .env.example. |
AUTH_SECRET |
Yes | NextAuth secret used to sign and decrypt session tokens. |
AUTH_ISSUER_URL |
Yes | Zitadel/AuthNEI issuer URL. |
AUTH_CLIENT_ID |
Yes | OAuth client ID for the hosted login flow. |
AUTH_CLIENT_SECRET |
Usually | OAuth client secret for the Zitadel provider. |
AUTH_SCOPES |
No | Defaults to openid email profile. |
AUTH_POST_LOGOUT_REDIRECT_URI |
Recommended | Redirect target after logout. Defaults to / if omitted. |
AUTH_DEBUG |
No | Set to true to enable verbose auth logging. |
The sample file also contains:
APP_BASE_URLAUTH_REDIRECT_URI
Those values may still be useful for external auth-provider setup, but they are not referenced directly by this frontend codebase.
Example local configuration:
NEXT_PUBLIC_BASE_URL=http://localhost:4000
AUTH_SECRET=replace-with-a-long-random-secret
AUTH_ISSUER_URL=https://auth.example.com
AUTH_CLIENT_ID=replace-with-your-client-id
AUTH_CLIENT_SECRET=replace-with-your-client-secret
AUTH_SCOPES=openid email profile
AUTH_POST_LOGOUT_REDIRECT_URI=http://localhost:3000
AUTH_DEBUG=falsepnpm devThe app runs on http://localhost:3000 by default.
Defined in package.json:
pnpm dev- start the Next.js development serverpnpm build- create a production buildpnpm start- start the production serverpnpm lint- run ESLint
Most meaningful pages depend on a live backend:
- subject lists are fetched from the API
- profile data is fetched from
/user - scoreboard data comes from backend score endpoints
- admin pages call protected admin endpoints
Without a reachable backend and valid auth configuration, the app will render incompletely or redirect away from protected routes.
The app uses a JWT session strategy:
- NextAuth stores the upstream access token and ID token in its JWT
- server helpers in
src/lib/server-auth.tsread those tokens from cookies - authenticated server components fetch user data from the backend before rendering
- the
/api/backend/*proxy forwards the bearer token to the upstream API
The root layout in src/app/layout.tsx wires up:
- global styles
- the top navigation bar
- auth context
- theme provider
- changelog popup
- cookie consent banner
No deployment manifests such as Dockerfile, vercel.json, render.yaml, or fly.toml are currently committed in this repository. That means deployment is flexible, but you need to provide the surrounding infrastructure yourself.
For production you need:
- a Node-compatible host capable of running
next buildandnext start - all auth-related environment variables
- a reachable backend API URL for
NEXT_PUBLIC_BASE_URL - a correctly configured callback and logout setup in Zitadel/AuthNEI
A typical production flow is:
pnpm install --frozen-lockfile
pnpm build
pnpm startIf you deploy behind a reverse proxy or managed platform, ensure:
- HTTPS is enabled
- your auth issuer accepts the production callback URL
AUTH_POST_LOGOUT_REDIRECT_URImatches the deployed frontend URL
Check:
AUTH_SECRETAUTH_ISSUER_URLAUTH_CLIENT_IDAUTH_CLIENT_SECRET- whether the issued access token is expired
The auth helper marks expired tokens with AccessTokenExpired, and protected routes will reject them.
Check:
NEXT_PUBLIC_BASE_URL- backend availability
- whether the backend accepts the forwarded bearer token
That usually means one of the following:
- there is no valid session token
- the upstream access token expired
- the backend
/admincheck returned a non-200 status
Contributions are welcome. Start with CONTRIBUTING.md for contribution workflow and expectations.
If you discover a vulnerability, read SECURITY.md before disclosing it.
This project is licensed under the GNU General Public License v3.0. See LICENSE.
- Email:
support.antirecurso@nei-isep.org - Public site: https://antirecurso.nei-isep.org