Development Pipeline
Quick Reference
| Purpose | macOS/Linux | Windows |
|---|---|---|
| Build everything | make build | .\build.ps1 build |
| Build backend only | make build_backend | .\build.ps1 build_backend |
| Build frontend only | make build_frontend | .\build.ps1 build_frontend |
| Package for distribution | ./build.sh package | .\build.ps1 package |
| Run everything (development) | make run | .\build.ps1 run |
| Run backend only | make run_backend | .\build.ps1 run_backend |
| Run frontend only | make run_frontend | .\build.ps1 run_frontend |
| Run all tests | make test | .\build.ps1 test |
| Run unit tests | make test_unit | .\build.ps1 test_unit |
| Clean build artifacts | make clean | .\build.ps1 clean |
| Lint code | make lint | .\build.ps1 lint |
| Lint documentation (Vale) | make lint_docs | — |
| Run all PR checks | make pr_checks | — |
Useful Commands
This section provides a reference for the standard development commands. While the examples below use make for cross-platform simplicity, all commands map directly to the underlying build scripts for your OS:
- Make (Cross-platform):
make <target> - Bash (Linux/macOS):
./build.sh <target> - PowerShell (Windows):
.\build.ps1 <target>
Building
Build everything (backend + frontend + docs + samples, etc.):
make build
Build only the backend:
make build_backend
Build only the frontend:
make build_frontend
Build with test coverage instrumentation:
make build_with_coverage
This will run unit tests, build with coverage flags, run integration tests, and generate a combined coverage report.
Building without Consent Server
By default, the build process downloads and packages the default consent server. If you want to skip this step, use the WITHOUT_CONSENT flag:
Using Make (Cross-platform)
# Build and test bypassing consent
make build WITHOUT_CONSENT=true
make test_integration WITHOUT_CONSENT=true
Using Bash (Linux/macOS)
./build.sh build --without-consent
Using PowerShell (Windows)
.\build.ps1 build --without-consent
Using Docker
docker build --build-arg WITH_CONSENT=false -t thunderid:latest .
If you build without the consent server, you must also disable it when running setup and starting the server, as the scripts default to WITH_CONSENT=true. Run setup and start with the appropriate flag for your platform:
Bash (Linux/macOS)
./setup.sh --without-consent
./start.sh --without-consent
PowerShell (Windows)
.\setup.ps1 --without-consent
.\start.ps1 --without-consent
Make
make run WITHOUT_CONSENT=true
Docker (environment variable)
docker run -e WITH_CONSENT=false thunderid:latest
Running
Run everything (backend + frontend):
make run
This automatically sets up the complete development environment with backend, frontend apps, and seed data.
If you built the project without the consent server, you must also run it with the flag to avoid startup errors:
make run WITHOUT_CONSENT=true
Run only the backend:
make run_backend
Run only the frontend:
make run_frontend
Testing
Run all backend tests (unit + integration):
make test
Run unit tests only:
make test_unit
Run integration tests only:
make test_integration
Run a specific integration test:
make test_integration RUN="TestName"
Run tests for a specific package:
make test_integration PACKAGE="pkg/path"
Run frontend unit tests:
cd frontend && pnpm test
make test only runs backend tests. Frontend and E2E tests must be run separately.
Code Coverage Requirements:
- Minimum: at least 80% code coverage for new code
- Encouraged: 100% coverage
E2E Tests (Playwright)
Use make test_e2e for a fully automated run. It starts the server, imports sample app resources, starts the sample app, and runs Playwright:
make test_e2e
Stop any running ThunderID instance before using make test_e2e. The script manages the full server lifecycle.
To run Playwright against an already-running server and sample app, run Playwright directly inside tests/e2e/:
cd tests/e2e
npx playwright test
Click to expand - Manual E2E Setup
1. Build the product
make build
This produces the server distribution and sample app packages under target/dist/.
2. Start the server
Extract the server distribution and run setup, then start:
mkdir -p tests/e2e/server
unzip "target/dist/thunderid-*.zip" -d tests/e2e/server
cd tests/e2e/server && ./setup.sh
./start.sh &
setup.sh starts the server temporarily with security disabled, runs the bootstrap scripts (which register default resources and sample app OAuth clients), and stops the server cleanly. start.sh then starts it with security enabled.
3. Extract sample apps and start the SDK sample
Extract the React Vanilla and React SDK sample packages and start the SDK sample app, which the e2e tests interact with:
cd <REPO_ROOT>
mkdir -p tests/e2e/sample-app-vanilla tests/e2e/sample-app-sdk
unzip "target/dist/sample-app-react-vanilla-*.zip" -d tests/e2e/sample-app-vanilla
unzip "target/dist/sample-app-react-sdk-*.zip" -d tests/e2e/sample-app-sdk
cd tests/e2e/sample-app-sdk && ./start.sh &
4. Install dependencies and browsers
cd tests/e2e
npm ci
npx playwright install --with-deps
5. Configure environment
Copy .env.example to .env and set your values:
cp .env.example .env
BASE_URL=https://localhost:8090
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin
TEST_USER_USERNAME=testuser
TEST_USER_PASSWORD=admin
ENVIRONMENT=local
# Sample app (used in social login / OAuth flow tests)
SAMPLE_APP_URL=https://localhost:3000
SAMPLE_APP_USERNAME=e2e-test-user
SAMPLE_APP_PASSWORD=e2e-test-password
# Mock SMS server port (used in MFA tests)
MOCK_SMS_SERVER_PORT=8098
6. Run the tests
cd tests/e2e
npx playwright test
E2E test options:
| Option | Command |
|---|---|
| All browsers | npx playwright test |
| Chromium only | npx playwright test --project=chromium |
| Accessibility tests only | npx playwright test --grep @accessibility |
| Smoke tests only | npx playwright test --grep @smoke |
| Watch in browser | npx playwright test --headed |
| Step through interactively | npx playwright test --debug |
| Interactive UI mode | npx playwright test --ui |
Linting
Lint backend code:
make lint_backend
This uses golangci-lint to check code quality and style.
Lint frontend code:
make lint_frontend
Lint documentation (Vale):
make lint_docs
Vale must be installed before running this command. On macOS, install it with:
brew install vale
For other platforms, download the binary from the Vale releases page.
This command runs Vale against the entire docs/ directory and may surface pre-existing issues in files you did not change. CI only checks files changed in your pull request, so focus on issues in files you have edited.
Lint backend, frontend, and SDKs:
make lint
PR Checks
Run all the checks that CI performs on pull requests in a single command:
make pr_checks
This runs the following checks in order:
| Step | Command | What it checks |
|---|---|---|
| Verify mocks | make verify_mocks | Mock files are in sync with interfaces |
| Lint | make lint | Backend, frontend, and SDK code quality |
| Format check | make format_check | Frontend code formatting |
| Backend unit tests | make test_unit | Backend unit test suite |
| Frontend unit tests | make test_frontend | Console and Gate app unit tests |
| Integration tests | make test_integration | API and database integration tests |
| Build backend | make build_backend | Backend compiles successfully |
| Build frontend | make build_frontend | Frontend compiles successfully |
| Build samples | make build_samples | Sample apps compile successfully |
Each step can also be run independently:
Check mock files are in sync:
make verify_mocks
This regenerates mocks from the current interfaces and fails if the result differs from what is committed.
Check frontend code formatting:
make format_check
Run frontend unit tests (console + gate):
make test_frontend
Run a security audit on dependencies:
make security_audit
This runs pnpm audit and npm audit at the high severity level. Note that CI applies additional ignore rules from .audit-ignore.json for known advisories; this local command may surface entries that CI suppresses.
Run E2E tests:
make test_e2e
This handles the full setup automatically. The script starts the server with security disabled, imports declarative resources for the sample apps, and restarts the server with security enabled. The script then builds and starts the sample app and runs Playwright. Stop any already-running ThunderID instance before using this command.
Generating Mocks
ThunderID uses mockery to generate mocks for unit tests.
Generate mocks:
make mockery
This will generate mocks based on the configurations in:
.mockery.public.yml- For public interfaces.mockery.private.yml- For private interfaces
Generated mocks are placed in backend/tests/mocks/.
CI has a verify-mocks job that will fail your build if mocks are out of sync with the interfaces. Always run make mockery after changing any interface. Use make verify_mocks to confirm they are in sync before pushing.
Other Commands
Clean build artifacts:
make clean
Build Docker images:
# Single-arch image with version tag
make docker-build
# Multi-arch image (amd64 + arm64)
make docker-build-multiarch
View all available commands:
make help
Advanced Setup (Manual Mode)
Click to expand - Manual Frontend Setup
For developers who want to run frontend components separately without using make run commands.
Installing Dependencies
- Navigate to the ThunderID frontend directory.
cd frontend
- Install the dependencies using
pnpm.
pnpm install
Building the Project
Execute the build command to compile the project. This will build all the necessary packages and applications.
pnpm build
Seed Data (Optional)
Note: This step is only necessary if you are running the backend server manually and have not yet set up the initial data.
If you have not already created the Console application and the default admin user, you can do so by running the following command:
API_BASE="https://localhost:8090" \
backend/cmd/server/bootstrap/01-default-resources.sh \
--console-redirect-uris "https://localhost:5191/console"
Setting up the ThunderID Gate Application
-
Point the
gate_clientindeployment.yamlto the local ThunderID Gate application.- If you are running
make run, change thegate_clientsection inbackend/cmd/server/repository/conf/deployment.yaml - If you are running the backend server manually, change the
gate_clientsection in<THUNDERID_HOME>/repository/conf/deployment.yaml
- If you are running
gate_client:
port: 5190
- Add the local development origin of the ThunderID Gate application (https://localhost:5190) to the CORS allowed origins in
<THUNDERID_HOME>/repository/conf/deployment.yaml.
cors:
allowed_origins:
- "https://localhost:5190"
- Run the ThunderID Gate application.
cd frontend
pnpm --filter @thunderid/gate dev
Setting up the ThunderID Console Application
IMPORTANT: This section assumes that you have already created the Console application using the initial data setup script. If not, please refer to the Seed Data section above.
- First, retrieve the application ID of the Console application from the ThunderID server. This will be the application with the
client_idCONSOLE.
curl -k -X GET "https://localhost:8090/applications"
- Then, get the current Console application configuration:
curl -k -X GET "https://localhost:8090/applications/<console-application-id>"
Note: Replace <console-application-id> with the actual application ID (e.g., 6100bc91-ba99-4ce9-87dd-6d4d80178c38) obtained from the previous step. The -k flag allows curl to work with self-signed SSL certificates in development.
- Copy the response from step 2 and update the
redirectUrisin the JSON object to include the local development URL (ex: https://localhost:5191/console). Locate theinboundAuthConfig > configsection and update theredirectUrisarray:
"redirectUris": [
"https://localhost:8090/console",
"https://localhost:5191/console"
]
- Update the Console application with the modified configuration by passing the updated JSON directly:
curl -k -X PUT "https://localhost:8090/applications/<console-application-id>" \
-H "Content-Type: application/json" \
-d '<paste-the-modified-json-here>'
- Add the local development origin of the console application (https://localhost:5191) to the CORS allowed origins in
<THUNDERID_HOME>/repository/conf/deployment.yaml.
cors:
allowed_origins:
- "https://localhost:5191"
- Run the ThunderID Console application.
pnpm --filter @thunderid/console dev
This will run the ThunderID Console application on https://localhost:5191/console.
Development Workflow
For area-specific coding standards, see the Backend Development and Frontend Development guides.
1. Make Your Changes
Follow coding guidelines and best practices:
- Backend: Review
.github/instructions/for package structure, services, data access, API handlers, and testing patterns - Frontend: See
.github/instructions/frontend.instructions.md - Security: Avoid SQL injection, XSS, command injection, and OWASP top 10 vulnerabilities
Best practices:
- Keep changes focused on a single issue
- Use meaningful variable/function names
- Add comments for complex logic
- Maintain consistency with existing code
2. Test and Validate Your Changes
Before committing, ensure code quality and correctness. Run everything CI will check with one command:
make pr_checks
Or run individual checks:
| Purpose | Command |
|---|---|
| All PR checks | make pr_checks |
| Backend unit tests | make test_unit |
| Backend integration tests | make test_integration |
| Backend all tests | make test |
| Frontend unit tests | make test_frontend |
| E2E tests (Playwright) | make test_e2e |
| Lint all code | make lint |
| Lint backend | make lint_backend |
| Lint frontend | make lint_frontend |
| Lint documentation (Vale) | make lint_docs |
| Check formatting | make format_check |
| Verify mock files | make verify_mocks |
| Security audit | make security_audit |
Requirements:
- All tests must pass
- Code coverage: at least 80% (higher encouraged)
- No linting errors
- Unit tests for business logic
- Integration tests for API endpoints
- Test edge cases and error scenarios
3. Commit Your Changes
Use clear, descriptive commit messages:
git commit -m "Fix token refresh failing after 30 minutes
Fixes #123"
Best practices:
- Make atomic commits (one logical change per commit) — ideally one commit per PR
- Write commit messages that explain why, not just what
- Reference the issue number using
Fixes #<number>orCloses #<number>
4. Push and Create PR
Push your changes to your forked repository:
git push origin <branch-name>
Then create a Pull Request to the upstream/main branch on GitHub:
- Go to your fork on GitHub
- Click "Compare & pull request"
- Provide a clear, descriptive title (e.g., "Add TOTP-based MFA support")
- Fill in the PR templates
- Link to the related issue
- Ensure all CI checks pass
5. Address Review Feedback
- Respond to reviewer comments promptly
- Keep commit history clean — rebase review fixes into the appropriate commit rather than adding separate "fix review comments" commits
- Push updates to the same branch
- Re-request review when ready
6. Merge
Once approved by maintainers and all checks pass, a maintainer will merge your PR.