AIMathTutor:基于 Quarkus 与 Vaadin 的交互式数学学习全栈应用
gregor-dietrich/aimathtutor
AIMathTutor 是一个交互式数学学习全栈 Web 应用,后端用 Quarkus、前端用 Vaadin,内置 Graspable Math 工作区,支持符号操作与分步解题。它提供 AI 实时辅导反馈、提示与自适应出题,可接入 Google、OpenAI、Ollama 或 mock,并支持课程与练习管理、分析仪表盘及细粒度用户角色权限。
AIMathTutor is a full-stack web application for interactive math learning, built with Quarkus (backend) and Vaadin (frontend). It features an embedded Graspable Math workspace, AI-powered tutoring, lesson/exercise management, analytics, and granular user roles.
🌟 Features
- Interactive Graspable Math workspace for symbolic manipulation and step-by-step actions
- Real-time AI tutor feedback, hints, and adaptive problem generation (Google, OpenAI, Ollama, mock)
- Problem and lesson authoring, organization, and progress tracking
- Threaded comments on exercises, moderation, and reporting
- Session/event tracking and analytics dashboards for teachers/admins
- Granular user management: users, groups, ranks, and permissions
- Tight Quarkus + Vaadin integration: CDI-injected services, no REST boundary for core logic
🚀 Getting Started
See Quickstart for setup and usage.
Deployment
When deploying to production, it is critical to override the default database password. Set the QUARKUS_DATASOURCE_PASSWORD environment variable to a strong password to replace the default changeit value used in dev/test profiles.
Never set a dev or test profile (QUARKUS_PROFILE, QUARKUS_CONFIG_PROFILE_PARENT) on a production deployment: those profiles drop and recreate the database tables, so the app refuses to start with one. Likewise, never override Hibernate's schema management (QUARKUS_HIBERNATE_ORM_SCHEMA_MANAGEMENT_STRATEGY, the deprecated QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION, or their quarkus.hibernate-orm... property forms): anything but validate or none makes the app refuse to start. In both cases the reason appears in docker compose logs app.
Recovering administrator access
The app refuses to delete, ban, deactivate or demote its last active administrator, or to remove a permission from their rank. An administrator is an activated, unbanned user whose rank has every permission: nobody can grant a permission their own rank lacks, so only such a user can give a rank back a permission it lost. If no active user's rank has every permission, for example because one was removed from the Admin rank before 4.0.14, the app protects nobody and can't fix that itself; open psql (step 2), run the user_ranks UPDATE from step 4 on its own and then COMMIT;. If no administrator can log in anyway (for example after a forgotten password), reset one directly in the database. You need a checkout of this repository and JDK 25 (./mvnw fetches Maven); the checkout you run docker compose from will do.
-
Run
make passwordand copy the printedhash=value. Choose a password that meets the app's rules, whichmake passworddoesn't enforce: 8 to 72 characters, with an uppercase and a lowercase letter, a digit and a symbol. -
Open psql in the database container. These are the
docker-compose.ymldefaults; use your values if you setSQL_USERNAMEorSQL_DATABASE:docker compose exec db psql -U aimathtutor -d aimathtutor -
List the users holding the Admin rank. Restoring every permission makes every active one of them an administrator, so review the list, especially after a compromise. To leave someone out, add
UPDATE users SET activated = FALSE WHERE username = '<other>';to the transaction in step 4:SELECT u.username, u.activated, u.banned FROM users u JOIN user_ranks r ON r.id = u.rank_id WHERE r.public_id = '01ARZ3NDEKTSV4RRFFQ69G5FAV';
-
Restore every permission of the Admin rank and reset the account (replace
<hash>and<name>; usernames are stored in lower case):BEGIN; UPDATE user_ranks SET admin_view = TRUE, exercise_add = TRUE, exercise_delete = TRUE, exercise_edit = TRUE, lesson_add = TRUE, lesson_delete = TRUE, lesson_edit = TRUE, comment_add = TRUE, comment_delete = TRUE, comment_edit = TRUE, user_add = TRUE, user_delete = TRUE, user_edit = TRUE, user_group_add = TRUE, user_group_delete = TRUE, user_group_edit = TRUE, user_rank_add = TRUE, user_rank_delete = TRUE, user_rank_edit = TRUE, ai_config_edit = TRUE WHERE public_id = '01ARZ3NDEKTSV4RRFFQ69G5FAV'; UPDATE users SET password = '<hash>', banned = FALSE, activated = TRUE, rank_id = (SELECT id FROM user_ranks WHERE public_id = '01ARZ3NDEKTSV4RRFFQ69G5FAV') WHERE username = '<name>';
Run
COMMIT;only if the usersUPDATEreportedUPDATE 1; otherwise runROLLBACK;and fix the name. The hash contains$, so type it inside psql or single quotes, never inside a double-quoted shell string, where the shell would expand it.If the Admin rank was deleted, the rank
UPDATEreportsUPDATE 0and the usersUPDATEfails on a NULLrank_id. RunROLLBACK;, pick another rank fromSELECT public_id, name FROM user_ranks;that no other active user holds, since every active holder becomes an administrator, and repeat steps 3 and 4 with itspublic_id. -
Restart the app with
docker compose restart app. This step is required: it clears the failed-login lockouts that the forgotten password has probably triggered, ends every open session at once (the new password ends the account's other sessions too, but only once their 30-second sign-in cache lapses, since a database edit doesn't notify the app), and drops the cached rank list, so the Ranks page doesn't show, and re-save, the old permissions.
If logging in fails with a server error after the reset, check that the app still mounts its original encryption key volume: a reset doesn't help when the key is lost.
Common Development Commands (via Makefile)
make dev– Start Quarkus in dev modemake test– Execute unit tests (skips integration tests)make coverage– Execute all tests (unit + integration) and generate JaCoCo reportmake build– Build the Docker images for the local image store (make check,mvn package, native-platformdocker build)make install–make checkandmvn clean install -DskipTestsmake password– Generate a bcrypt hash for a password (for init.sql or an administrator reset)make release– Pull from origin/main, test,make tag, and build and push multi-platform Docker images withdocker buildxmake branch,make tag,make rebase,make untag– Git branch/tag management
See the Makefile or use make help for all available commands and scripts.
🤖 Supported AI Providers
Configuration:
- API Keys: Set properties
app.google.api.key,app.openai.api.key, andapp.openai.organization-id(immutable at runtime). - Provider Settings (model, base URL, temperature, prompts, etc.): Configure via the Admin Settings UI at
/admin/configafter login (runtime-mutable, database-backed). - Encryption key: Resolution order: (1)
app.security.encryption-key-fileproperty, (2)$XDG_DATA_HOME/aimathtutor/encryption.key, (3)~/.aimathtutor/encryption.key, (4) auto-generate a 256-bit key at the XDG path with 0600 permissions. In Docker, mount theaimathtutor_keysvolume at/etc/aimathtutor/keys. This key encrypts PII fields (such as user email) at rest.
See docs/QUICKSTART.md and docs/BUILD_GUIDE.md for detailed setup instructions.
📖 Documentation
🛠️ Project Structure & Workflow
- Monolithic Quarkus + Vaadin app
- Vaadin views inject backend services via CDI (
@Inject) - Graspable Math workspace embedded via Vaadin and JavaScript API
- AI Tutor layer supports Google, OpenAI, Ollama, and mock providers
- Entities, DTOs, services and views organized by resource type
- See Project Instructions for coding standards and architecture
来源:GitHub · github.com