Before running the application for the first time, configure your OAuth credentials:
cp .env.SAMPLE .env
Then fill in the values in .env:
| Variable | Description | Setup Guide |
|---|---|---|
GOOGLE_CLIENT_ID |
Google OAuth client ID | docs/oauth.md |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret | docs/oauth.md |
ADMIN_EMAILS |
Comma-separated admin email addresses | docs/oauth.md |
See docs/oauth.md for full setup instructions, including Dokku deployment.
Open two terminal windows:
# Terminal 1 – backend
mvn spring-boot:run# Terminal 2 – frontend
cd frontend
npm install # first time only
npm startThe app is available at http://localhost:8080. Use port 8080 (not 3000) so that Google OAuth redirects work correctly.
mvn testIntegration tests start a real Spring Boot server on port 8080, mock Google OAuth via WireMock on port 8090, and drive a headless Chromium browser with Playwright.
Prerequisites:
-
Install Playwright browsers (one-time setup):
mvn test-compile exec:java -e \ -Dexec.mainClass=com.microsoft.playwright.CLI \ -Dexec.classpathScope=test \ -Dexec.args="install chromium" -
Run with the integration flag:
INTEGRATION=true mvn -ntp -B test-compile failsafe:integration-test failsafe:verify
To run with a visible browser (useful for debugging):
INTEGRATION=true HEADLESS=false mvn -ntp -B test-compile failsafe:integration-test failsafe:verify
The integration tests are in src/test/java/edu/ucsb/cs/scaffold/web/:
| Test class | What it verifies |
|---|---|
OauthWebIT |
User can log in and log out via mock OAuth |
HomePageWebIT |
After login, the concept graph is visible on the home page |
To run the full app with WireMock replacing Google OAuth (useful for local frontend development without real Google credentials):
mvn spring-boot:run -Dspring-boot.run.profiles=wiremockThe app starts with a pre-configured admin user (admingaucho@ucsb.edu). Navigate to
http://localhost:8080 and use the mock login page at http://localhost:8090/oauth/authorize.
When running locally with:
mvn spring-boot:runthe H2 console is available at:
http://localhost:8080/h2-console
Use these login values:
- JDBC URL:
jdbc:h2:file:./target/db-development - Username:
sa - Password: (leave blank)
This project uses Liquibase for schema management and data migrations.
- Master changelog:
src/main/resources/db/migration/changelog-master.json - Individual migrations:
src/main/resources/db/migration/changes/*.json
- Development: runs automatically on app startup against the development datasource.
- Test: runs automatically before tests against the test datasource.
- Production: runs automatically on app startup against PostgreSQL.
Spring is configured with:
spring.jpa.hibernate.ddl-auto=nonespring.liquibase.change-log=db/migration/changelog-master.json
Current migrations include:
- Initial schema creation for current tables.
- Legacy migration from pin-based schema to userid-based schema.
- Legacy PostgreSQL constraint-name normalization.
- Add a new JSON changelog file in
src/main/resources/db/migration/changes/. - Use an incremental numeric prefix (for example
004-...json). - Prefer preconditions (
onFail: MARK_RAN) for compatibility with partially migrated environments. - Start the app or run tests to validate the migration.
- Inspect Liquibase tracking tables in your database:
DATABASECHANGELOGDATABASECHANGELOGLOCK
In local development, you can view these tables from the H2 console.
For the development profile, the local H2 file lives under target/.
Use the helper script:
./scripts/reset-local-h2.shTo reset and immediately start the app:
./scripts/reset-local-h2.sh --runManual equivalent:
- Stop the app.
- Delete local H2 files:
target/db-development.mv.dbtarget/db-development.trace.db(if present)
- Start the app again with
mvn spring-boot:run.
Liquibase will recreate the schema and reapply migrations.
- Checksum mismatch: if a previously applied changelog file was edited, Liquibase will fail validation. Preferred fix is to add a new migration file instead of modifying an already-applied one.
- Partially migrated environment: use strong preconditions with
onFail: MARK_RANin migration files so old/new states can both be handled safely. - Locked changelog: if
DATABASECHANGELOGLOCKis stuck after an interrupted run, clear the lock row in your local/dev database and restart.