Academic degree planning for Al Akhawayn University.
Registering at Al Akhawayn means filling a paper form by hand, walking it to your advisor's office, and coming back later if there's a queue.
The walking isn't the problem. The problem is that while you're filling in that form, you can't answer the questions that actually matter. Did I finish the prerequisite for this one? Is it even offered in spring? How many credits do I still owe for my minor? Am I going to graduate on time? The form doesn't know. The program sheet is a PDF that can't see your transcript. So you ask a friend in your major, or whoever's ahead of you in the queue, write something down, and hope. If it's wrong, you find out weeks later.
goPlan replaces that with a plan that knows your record:
- Requirements checked against your real transcript, not a PDF — what's done, what's left, how far along you are.
- Prerequisites flagged as you plan, the moment you add a course, instead of weeks after you submit.
- No form and no office trip — submit the semester and it lands in your advisor's queue, with your full transcript beside it so they can actually judge it.
- Ask the AI advisor what to take first or whether a term is too heavy, and get an answer from your own record rather than someone else's guess.
- Try before you commit with draft plans: add a minor, push a course to summer, see what it does to your graduation date.
Registration was never the hard part. Deciding without being able to see anything was.
- transcript and degree-progress view;
- drag-and-drop semester planning;
- prerequisite and credit-load feedback;
- recommended courses;
- draft plans;
- AI-assisted course and plan questions;
- selectable AI change previews with atomic apply and safe undo.
- advisee/caseload views;
- student plan review;
- approvals and auditable prerequisite, requirement, and substitution overrides;
- plan and audit history.
- course and prerequisite management;
- course offering rules by academic term;
- degree-program and requirement management;
- semester configuration;
- user and role management.
Next.js application
├── React UI
├── API routes
│ ├── authentication and refresh tokens
│ ├── student planning
│ ├── advisor review
│ ├── administration
│ └── DeepSeek-assisted planning
├── deterministic domain rules
└── MySQL
Authentication uses short-lived JWT access tokens and revocable opaque refresh tokens stored in MySQL. Passwords are hashed with bcrypt. Role checks are applied within protected API routes.
AI output is treated as a proposal. Students preview and select proposed actions before applying them. The server then revalidates ownership, locked or protected semesters, duplicates, credit limits, prerequisites, and configured course offerings before applying the entire change set in one transaction. A saved pre-change snapshot supports undo while the plan has not changed again.
AI chat routes are authenticated and use persistent, per-user request limits. Operational telemetry records status, timing, and usage counts, but not prompt or response bodies.
- Next.js 16 and React 19
- TypeScript
- MySQL 8
- DeepSeek API with a configurable model
- Tailwind CSS and shadcn/ui
- Zod, bcrypt, and JSON Web Tokens
- Node.js 20+
- npm
- MySQL 8+
- a DeepSeek API key for AI features
git clone https://github.com/OmarTaheri/goPlan.git
cd goPlan
npm install
cp .env.example .env.localConfigure .env.local:
DB_HOST=localhost
DB_PORT=3306
DB_USER=goplan
DB_PASSWORD=replace-me
DB_NAME=goplan
JWT_ACCESS_SECRET=generate-a-long-random-value
JWT_REFRESH_SECRET=generate-a-different-long-random-value
JWT_ACCESS_EXPIRY=15m
JWT_REFRESH_EXPIRY=7d
DEEPSEEK_API_KEY=replace-me
DEEPSEEK_MODEL=deepseek-v4-pro
AI_RATE_LIMIT_REQUESTS=20
AI_RATE_LIMIT_WINDOW_SECONDS=900
AI_PLANNER_CHAT_RATE_LIMIT_REQUESTS=10
AI_PLANNER_CHAT_RATE_LIMIT_WINDOW_SECONDS=900
AI_COURSE_CHAT_RATE_LIMIT_REQUESTS=30
AI_COURSE_CHAT_RATE_LIMIT_WINDOW_SECONDS=900
NODE_ENV=developmentCreate and seed a fresh local database (schema.sql drops and recreates goplan):
mysql -u root -p < database/schema.sql
mysql -u root -p goplan < database/population.sqlFor an existing database, apply the migrations instead of recreating it:
mysql -u root -p goplan < database/migrations/20260810_plan_approval_identity.sql
mysql -u root -p goplan < database/migrations/20260810_ai_usage_and_rate_limits.sql
mysql -u root -p goplan < database/migrations/20260810_ai_plan_changes_and_overrides.sql
mysql -u root -p goplan < database/migrations/20260810_ai_plan_integrity.sqlStart the application:
npm run devOpen http://localhost:3000.
Run the automated checks:
npm test
npm run lint
npm run buildThe repository ships a multi-stage Dockerfile built on Next.js standalone output, so the runtime image carries only the server and the dependencies it actually traces.
docker build -t goplan .
docker run -p 3000:3000 --env-file .env.local goplan- Create a new Application pointing at this repository and select the Dockerfile build pack. No build command or start command is needed.
- Set the exposed port to
3000. - Add the environment variables from
.env.example— at minimumDB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAME,JWT_ACCESS_SECRET, andJWT_REFRESH_SECRET. Secrets are read at runtime, never baked into the image. - Point the health check at
/api/health. It returns200only when the process is up and the database answers, so a rolling deploy will not take traffic before its dependencies are ready. - Create the schema before the first boot — see below.
The database is MySQL (the app uses the mysql2 driver; the schema uses AUTO_INCREMENT, SET FOREIGN_KEY_CHECKS, and other MySQL-only syntax). It will not run on PostgreSQL. Point the app at a database that already exists — MySQL does not create one on connect.
The container sets itself up on boot. Before the server starts, it applies database/deploy/01_schema.sql, creating any missing tables. Add DB_AUTO_SEED=true and it will also load the demo catalogue, but only into a database with no users. Nothing else is needed.
| Variable | Default | Effect |
|---|---|---|
DB_AUTO_MIGRATE |
true |
Create missing tables. Safe to leave on: re-running only adds what is absent. |
DB_AUTO_SEED |
false |
Load the demo catalogue into an empty database. Ignored once users exist. |
DB_SEED_FORCE |
false |
Seed even when data exists. Destroys all GoPlan data. |
DB_INIT_TIMEOUT |
120 |
Seconds to wait for the database before giving up. |
Seeding is guarded because 02_seed.sql truncates all 19 GoPlan tables. Leaving DB_AUTO_SEED=true set permanently is safe — after the first run the database has users and the seed is skipped, so a restart or redeploy will not wipe real data. Only DB_SEED_FORCE=true overrides that.
To load the scripts by hand instead, run them against your database directly:
mysql -h HOST -P PORT -u USER -p DBNAME < database/deploy/01_schema.sqlThe development scripts database/schema.sql and database/population.sql are for local use only: the first runs DROP DATABASE IF EXISTS goplan, and both hard-code USE goplan, so they ignore whichever database name your host assigned and will destroy an existing goplan database.
database/migrations/ is only for upgrading a database created before those features existed. 01_schema.sql already includes every migration, so a fresh install must not run them.
With schema but no demo data, create your first admin directly:
INSERT INTO users (username, email, password_hash, first_name, last_name, role)
VALUES ('admin', 'you@example.com', '<bcrypt hash>', 'Your', 'Name', 'ADMIN');The population scripts contain synthetic users for local development.
Never deploy the seeded passwords to a public or production environment. Replace or remove every seeded account before deployment.
database/
├── schema.sql
├── population.sql
├── migrations/
└── population/
src/
├── app/
│ ├── api/
│ └── dashboard/
├── components/
└── lib/
├── auth/
├── db/
├── domain/
└── middleware/
- Admin-configured semester dates are authoritative; conservative fallback dates are used only when a term has not been configured yet.
- Unit coverage exists for AI proposal validation, transaction rules, academic policy, and rate-limit policy, but broader end-to-end coverage is still needed.
- Course availability is authoritative only when an administrator configures it; otherwise the application reports it as unknown.
- Course availability and degree rules remain specific to the included AUI dataset.
- Admin-managed academic calendar with safe fallback dates
- Unit tests for AI prerequisites, availability, credit limits, and academic policy
- Integration tests for student/advisor approval flows
- Authentication and persistent rate limiting for AI routes
- Schema validation plus deterministic verification of AI-proposed actions
- CI for formatting, linting, tests, and production builds
- Sanitized public demo deployment
The repository currently contains an MIT license naming a different copyright holder. Confirm the upstream source and preserve any required attribution before presenting or relicensing the project.
