Project conventions, architecture, and coding patterns for the StreamPark codebase.
StreamPark is a Maven multi-module project with four top-level modules. Each has a clear responsibility boundary.
-
streampark-common(streampark-common/): Shared foundation layer. Contains configuration management (ConfigKeys,ConfigOption), utility classes (Utils,HadoopUtils,JsonUtils,YarnUtils), file system abstraction (FsOperator,HdfsOperator,LfsOperator), and shared enums (FlinkDeployMode,ApplicationType, etc.). Must be engine-agnostic — no Flink or Spark core API dependencies. All other modules depend on this module. -
streampark-flink(streampark-flink/): Flink development framework and runtime integration. Contains the core development API (FlinkStreaming,FlinkTable,FlinkSQL), version-specific shims layers (streampark-flink-shims_flink-1.xx), job submission clients (streampark-flink-client), Kubernetes integration (streampark-flink-kubernetes), application packer (streampark-flink-packer), and connectors. The shims proxy (FlinkShimsProxy) is the central mechanism for multi-version Flink support. -
streampark-spark(streampark-spark/): Spark development framework. Optional module, activated via-PsparkMaven profile. ContainsSparkStreaming,SparkBatchcore traits, Spark SQL client, and connectors. Follows the same lifecycle pattern as Flink modules. -
streampark-console(streampark-console/): Web management platform. Contains two submodules:streampark-console-service: Spring Boot 2.7 backend, withbase/(infrastructure),core/(business logic, controllers, services), andsystem/(authentication, user/role/team management) packages.streampark-console-webapp: Vue 3 + Vite frontend, withapi/(API layer),views/(pages),components/(reusable UI),store/(Pinia state).
The streampark-common module has the strongest stability guarantees — changes here affect all other modules. streampark-flink/streampark-flink-core public API (the FlinkStreaming, FlinkTable traits) should also be treated as stable — breaking changes require careful migration planning.
-
FlinkShimsProxy: The multi-version classloader isolation mechanism. UsesChildFirstClassLoaderto dynamically load version-specific shims JARs. Cached per Flink version. Changes here affect all Flink jobs across all versions. Never introduce static state that could leak across classloader boundaries. -
FlinkStreaming/FlinkTablelifecycle: Themain->init->ready->handle->destroylifecycle is the contract all user applications depend on. Changes to the execution order or initialization behavior can break existing applications in production. -
ConfigKeys/CommonConfig: Central configuration key definitions. Adding, removing, or renaming keys affects application configuration files, the console UI, and deployment scripts. Key names must remain backward-compatible. -
FlinkApplicationController/FlinkApplicationManageService/FlinkApplicationActionService: The core application management flow. Operations (start, stop, cancel, deploy) must be idempotent and handle all Flink states correctly. TheAppChangeEventannotation triggers state synchronization. -
SQL parsing and validation (
FlinkSql,FlinkSqlService,SqlConvertUtils): SQL validation must be version-aware (Flink 1.12-1.20 have different SQL syntax). Thesql-rev.dictfile handles MySQL-to-PostgreSQL dialect conversion. -
Kubernetes integration (
FlinkK8sWatchController): Uses Caffeine caches (TrackIdCache,JobStatusCache,MetricCache) for tracking K8s-deployed Flink jobs. Cache invalidation and TTL must be correct to avoid stale state. -
Database schema changes: All schema changes must have corresponding upgrade scripts in
streampark-console/.../script/upgrade/for both MySQL and PostgreSQL. Thesql-rev.dictfile must be updated if new SQL dialect differences are introduced. -
Authentication & Authorization:
ShiroConfig,JWTUtil,ShiroRealm— changes here affect all user access. The@Permissionannotation andPermissionAspectenforce team-level resource isolation. Never weaken RBAC checks.
-
Lifecycle trait pattern:
FlinkStreaming,FlinkTable,SparkStreaming,SparkBatchall follow the same trait-based lifecycle:main->init->ready->handle->start->destroy. Users overridehandle()(required) and optionallyready(),config(),destroy(). Never add mandatory lifecycle methods to existing traits. -
Shims / Proxy pattern:
FlinkShimsProxy.proxy(flinkVersion, func)isolates version-specific Flink API calls behind aChildFirstClassLoader. Each Flink version has its own shims module (streampark-flink-shims_flink-1.xx) with the same interface. New shims methods must be added to all version modules. -
Service layer separation: Console services are split by responsibility —
FlinkApplicationManageService(CRUD),FlinkApplicationActionService(start/stop/cancel),FlinkApplicationInfoService(query/info). Follow this pattern when adding new application operations. -
Implicit enrichment: Scala
implicitconversions are used to extend Flink/Spark APIs (e.g.,DataStreamExtadds methods toDataStream). New implicit conversions must be scoped to avoid polluting the global namespace. -
MyBatis-Plus entity pattern: Entities extend
BaseEntity(auto-fillcreateTime/modifyTime). Mappers extend MyBatis-PlusBaseMapper. Pagination usesMybatisPager+PaginationInterceptor. Follow existing patterns rather than introducing new ORM approaches. -
Enum-based configuration: Both Java enums (
FlinkDeployMode,ApplicationType) and Scala enumeratum enums (ApiType,PlannerType) are used. Prefer Scalaenumeratumfor new Scala-side enums — it provides better type safety and serialization. -
REST response pattern: All controller methods return
RestResponse.success(data)orRestResponse.fail(...). Never return raw objects. Use@Permissionannotation for access control,@AppChangeEventfor state-change auditing. -
File system abstraction: Use
FsOperator(withHdfsOperator/LfsOperatorimplementations) for file operations. Never use rawjava.io.Fileor HadoopFileSystemdirectly in business logic.
- Formatting: Eclipse formatter via Spotless (
tools/checkstyle/spotless_streampark_formatter.xml). Run./mvnw spotless:applybefore committing. - Import order:
org.apache.streampark,org.apache.streampark.shaded,org.apache,javax,java,scala,\#(all others). - Static checks: Checkstyle (
tools/checkstyle/checkstyle.xml) + Spotless. No wildcard imports. No@authortags. No JUnit 4 imports. - Lombok: Use
@Slf4j,@Data,@Builderwhere appropriate. Do not use@EqualsAndHashCodeon JPA/Hibernate entities. - Testing: JUnit 5 (
org.junit.jupiter) + AssertJ. Use@Test(not@Testfrom JUnit 4). UseassertThat(...).isEqualTo(...)style. Test classes should be in the same package as the code under test. - Package structure: Controllers in
controller/, service interfaces inservice/, implementations inservice/impl/, entities inentity/, mappers inmapper/, enums inenums/.
- Formatting: Scalafmt 3.7.5 (
tools/checkstyle/.scalafmt.conf). Max column 160. Run./mvnw spotless:applyto format. - Import ordering:
org.apache.streampark.*first, then other third-party, thenjavax.*,java.*,scala.*. - Static checks: Scalastyle (
tools/checkstyle/scalastyle-config.xml). No wildcard imports. Noprintlnstatements (useLoggertrait). - Testing: ScalaTest 3.2.9. Use
FlatSpecorFunSuitestyle consistent with existing tests. - Style: Use
valovervar. PreferOptionovernullin public APIs. Uselazy valfor expensive initialization. Use pattern matching instead ofisInstanceOf/asInstanceOf.
- Formatting: ESLint + Prettier. Run
pnpm lint:eslintandpnpm lint:prettier. - Vue 3 Composition API: Use
<script setup lang="ts">for new components. Use Pinia for state management (not Vuex). - API layer: All HTTP calls go through
src/api/modules usingdefHttp. API URLs are defined as enum constants. Never useaxiosorfetchdirectly in components. - Component naming: PascalCase for component files and names. Use
index.tsbarrel exports in component directories. - Unused variables: Prefix with
_to suppress ESLint warnings (argsIgnorePattern: '^_').
- Apache License header: Required on all new files. Use the copyright header from
tools/checkstyle/copyright.txt. Enforced by Spotless and Apache RAT. - No wildcard imports: Prohibited in both Java and Scala (enforced by Spotless).
- No personal pronouns in comments: Use descriptive, impersonal documentation.
- Database: Support both MySQL and PostgreSQL. All new SQL must be tested against both. Use
sql-rev.dictfor dialect differences. - Logging: Use Lombok
@Slf4j(Java) orLoggertrait (Scala). Uselog.info/log.errorwith parameterized messages. Never log credentials or sensitive data.
-
Full build (backend + frontend, skip tests):
./build.sh
Equivalent to:
./mvnw -Pshaded,webapp,dist -DskipTests clean install -
Fast build (backend only, skip all checks):
./mvnw -Pfast clean install -DskipTests
-
Build with Spark module:
./mvnw -Pspark,shaded clean install -DskipTests
-
Build backend only:
./mvnw clean install -DskipTests -pl '!streampark-console/streampark-console-webapp' -
Run single test class (Java):
./mvnw test -pl streampark-console/streampark-console-service -Dtest=FlinkApplicationControllerTest -
Run single test class (Scala):
./mvnw test -pl streampark-common -Dtest=org.apache.streampark.common.util.CommandUtilsTest -
Format code (Java + Scala):
./mvnw spotless:apply
-
Check formatting:
./mvnw spotless:check
-
Run Checkstyle:
./mvnw checkstyle:check
-
Frontend development server:
cd streampark-console/streampark-console-webapp && pnpm dev
-
Frontend lint:
cd streampark-console/streampark-console-webapp && pnpm lint:eslint && pnpm lint:prettier
-
Frontend build:
cd streampark-console/streampark-console-webapp && pnpm build
-
Run Docker Compose (local):
docker compose -f docker/docker-compose.yaml up -d
- PR title format:
[Module] Description(e.g.,[Flink] Fix shims classloader isolation,[Console] Add team-level resource filtering,[Common] Support Hadoop 3.x configuration). - Module prefixes:
[Common],[Flink],[Spark],[Console],[K8s],[Docs],[CI],[Build]. - One concern per PR: Unrelated whitespace, import, or formatting changes go in separate PRs. Do not mix refactoring with feature work.
- Commit messages: Describe the what and why, not implementation details. Reference related GitHub issues with
#xxx. - Apache License header: Required on all new files (enforced by Spotless and Apache RAT). The
spotless:checkandapache-rat:checkgoals run in CI. - Schema changes: Must include upgrade scripts for both MySQL and PostgreSQL in
streampark-console/.../script/upgrade/. - New shims methods: When adding a new method to the shims interface, add implementations to all version-specific shims modules (
streampark-flink-shims_flink-1.12throughstreampark-flink-shims_flink-1.20).
- Never modify
.asf.yaml,LICENSE,NOTICE, or.gitignorewithout explicit discussion. - Never upgrade Flink, Spark, Scala, Spring Boot, or other major dependency versions without discussion — these changes have broad impact across the entire project.
- Never remove or rename keys in
ConfigKeysorCommonConfig— these are user-facing configuration contracts. - Never change the
FlinkStreaming/FlinkTablelifecycle method signatures — this breaks all user applications. - Never add new required lifecycle methods to the
FlinkStreaming/FlinkTabletraits. - Never commit secrets, credentials, API keys, or cloud-specific tokens.
- Never introduce a new Flink version shims module without adding the corresponding CI build configuration.
- Never add a new database migration without providing both MySQL and PostgreSQL upgrade scripts.
- Never change the
SqlConvertUtilsdialect conversion logic without testing against both MySQL and PostgreSQL.
- Ask first before adding new third-party dependencies — license compatibility with Apache 2.0 matters.
- Ask first before promoting package-private classes/methods to public.
- Ask first before adding new Maven modules or restructuring the module hierarchy.
- Ask first before introducing new Scala implicits in the
commonmodule — they affect all downstream code. - Ask first before changing the authentication model (Shiro/JWT/Pac4j configuration).