This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git
The following commit(s) were added to refs/heads/master by this push:
new 684616e792 [docs] Reorganize project guides and add SVG diagrams
(#9734)
684616e792 is described below
commit 684616e792f9e9ef3e4b3d5bc0156b233a29d47d
Author: Jingsong Lee <[email protected]>
AuthorDate: Fri Sep 11 14:17:39 2026 +0800
[docs] Reorganize project guides and add SVG diagrams (#9734)
---
docs/docs/project/committer.md | 24 +-
docs/docs/project/contributing.md | 283 ++++++++-------------
docs/docs/project/creating-a-release.md | 166 ++----------
docs/docs/project/download.mdx | 85 ++++---
docs/docs/project/index.md | 35 +++
docs/docs/project/publishing-a-release.md | 156 ++++++++++++
docs/docs/project/releases.md | 159 ++++++++++++
docs/docs/project/security.md | 12 +-
docs/docs/project/verifying-a-release-candidate.md | 28 +-
docs/sidebars.js | 24 +-
docs/static/img/project/contribution-workflow.svg | 55 ++++
docs/static/img/project/release-artifacts.svg | 83 ++++++
docs/static/img/project/release-lifecycle.svg | 55 ++++
13 files changed, 797 insertions(+), 368 deletions(-)
diff --git a/docs/docs/project/committer.md b/docs/docs/project/committer.md
index bcf8ec9377..d4899305b8 100644
--- a/docs/docs/project/committer.md
+++ b/docs/docs/project/committer.md
@@ -24,16 +24,20 @@ under the License.
# Committer
+Committers help maintain Paimon's code and community. This guide explains how
+contributors are nominated and the judgment expected when using repository
+write access. Start with [Contributing](./contributing.md) for ways to
participate.
+
## Become a Committer
-#### How to become a committer
+### How nominations work
There is no strict protocol for becoming a committer. Candidates for new
committers are typically people that are
active contributors and community members. Candidates are suggested by current
committers or PMC members, and
voted upon by the PMC.
-If you would like to become a committer, you should engage with the community
and start contributing to Apache Paimon in
-any of the above ways. You might also want to talk to other committers and ask
for their advice and guidance.
+If you would like to become a committer, you should engage with the community
and start contributing to Apache Paimon through
+code or community work. You might also want to talk to other committers and
ask for their advice and guidance.
- Community contributions include helping to answer user questions on the
mailing list, verifying release candidates,
giving talks, organizing community events, and other forms of evangelism and
community building. The "Apache Way" has
@@ -44,7 +48,7 @@ any of the above ways. You might also want to talk to other
committers and ask f
and other help in identifying and fixing bugs. Especially constructive and
high quality design discussions, as well
as helping other contributors, are strong indicators.
-#### Identify promising candidates
+### Qualities of a committer
While the prior points give ways to identify promising candidates, the
following are "must haves" for any committer candidate:
@@ -57,9 +61,19 @@ While the prior points give ways to identify promising
candidates, the following
- They have shown to be respectful towards other community members and
constructive in discussions.
+## Working as a committer
+
+Use the [code review guide](./contributing.md#code-review-guide) when
evaluating
+contributions, and ask another reviewer when a change reaches beyond your
+expertise. Help contributors understand review feedback and reach agreement on
+the approach.
+
+Committers can also help [verify release
candidates](./verifying-a-release-candidate.md).
+The [release overview](./releases.md) explains the RM and voter
responsibilities.
+
## Committer Rights
JetBrains provides a free license to Apache Committers, allowing them to
access all JetBrains IDEs, such as
IntelliJ IDEA, PyCharm, and other desktop tools.
-Please use your @apache.org email address to [All Products Packs for Apache
committers](https://www.jetbrains.com/shop/eform/apache?product=ALL).
+Use your `@apache.org` email address to apply through [All Products Packs for
Apache committers](https://www.jetbrains.com/shop/eform/apache?product=ALL).
diff --git a/docs/docs/project/contributing.md
b/docs/docs/project/contributing.md
index 99920ab95f..7471e180d4 100644
--- a/docs/docs/project/contributing.md
+++ b/docs/docs/project/contributing.md
@@ -24,200 +24,131 @@ under the License.
# Contributing
-Apache Paimon is developed by an open and friendly community. Everybody is
cordially welcome to join
-the community and contribute to Apache Paimon. There are several ways to
interact with the community and contribute
-to Paimon including asking questions, filing bug reports, proposing new
features, joining discussions on the mailing
-lists, contributing code or documentation, improving website, testing release
candidates and writing corresponding blog etc.
+Apache Paimon welcomes contributions of code, documentation, testing, reviews,
+and community support. Start with a task below, and discuss questions in the
+relevant issue or on the [mailing
lists](https://github.com/apache/paimon#mailing-lists).
## What do you want to do?
-Contributing to Apache Paimon goes beyond writing code for the project. Below,
we list different opportunities to help the project:
-
-<table class="table table-bordered">
- <thead>
- <tr>
- <th>Area</th>
- <th>Further information</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><span class="glyphicon glyphicon-exclamation-sign"
aria-hidden="true"></span> Report Bug</td>
- <td>To report a problem with Paimon, open <a
href="https://github.com/apache/paimon/issues">Paimon's issues</a>. <br/>
- Please give detailed information about the problem you encountered and,
if possible, add a description that helps to reproduce the problem.</td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-console" aria-hidden="true"></span>
Contribute Code</td>
- <td>Read the <a href="#code-contribution-guide">Code Contribution
Guide</a></td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> Code
Reviews</td>
- <td>Read the <a href="#code-review-guide">Code Review Guide</a></td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-thumbs-up"
aria-hidden="true"></span> Release Version</td>
- <td>Releasing a new Paimon version.</td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-user" aria-hidden="true"></span>
Support Users</td>
- <td>Reply to questions on the <a
href="https://github.com/apache/paimon#mailing-lists">user mailing list</a>,
- check the latest issues in <a
href="https://github.com/apache/paimon/issues">Issues</a> for tickets which are
actually user questions.
- </td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-volume-up"
aria-hidden="true"></span> Spread the Word About Paimon</td>
- <td>Organize or attend a Paimon Meetup, contribute to the Paimon blog,
share your conference, meetup or blog
- post on the <a
href="https://github.com/apache/paimon#mailing-lists">[email protected]
mailing list</a>.
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <span class="glyphicon glyphicon-question-sign"
aria-hidden="true"></span> Any other question? Reach out to the
- <a
href="https://github.com/apache/paimon#mailing-lists">[email protected]
mailing list</a> to get help!
- </td>
- </tr>
- </tbody>
-</table>
+
+| Contribution | How to start |
+| --- | --- |
+| Ask or answer a question | Use the [user mailing
list](https://github.com/apache/paimon#mailing-lists), or help users in
existing issues. |
+| Report a bug | Open a [GitHub
issue](https://github.com/apache/paimon/issues) with the Paimon and engine
versions, expected and actual behavior, and a minimal reproduction. Remove
credentials from logs and configuration. |
+| Report a possible vulnerability | Follow the private [security reporting
process](./security.md#reporting-security-issues). |
+| Propose a feature | Explain the use case and design in an issue or on
`[email protected]` before implementation. |
+| Contribute code | Follow the [code contribution
guide](#code-contribution-guide). |
+| Improve documentation | Describe what readers need, update the relevant
page, and [build the documentation](#documentation-changes). |
+| Review code | Use the [code review guide](#code-review-guide). |
+| Test a release candidate | Follow the [verification
guide](./verifying-a-release-candidate.md) and report the checks you completed.
|
+| Help the community grow | Write about Paimon, organize or attend a meetup,
and share useful material on `[email protected]`. |
## Code Contribution Guide
-Apache Paimon is maintained, improved, and extended by code contributions of
volunteers. We welcome contributions to Paimon.
-
-Please feel free to ask questions at any time. Either send a mail to the Dev
mailing list or comment on the issue you are working on.
-
-<style>
-.contribute-grid {
- margin-bottom: 10px;
- display: flex;
- flex-direction: column;
- margin-left: -2px;
- margin-right: -2px;
-}
-
-.contribute-grid .column {
- margin-top: 4px;
- padding: 0 2px;
-}
-
-@media only screen and (min-width: 480px) {
- .contribute-grid {
- flex-direction: row;
- flex-wrap: wrap;
- }
-
- .contribute-grid .column {
- flex: 0 0 50%;
- }
-
- .contribute-grid .column {
- margin-top: 4px;
- }
-}
-
-@media only screen and (min-width: 960px) {
- .contribute-grid {
- flex-wrap: nowrap;
- }
-
- .contribute-grid .column {
- flex: 0 0 25%;
- }
-}
-
-.contribute-grid .panel {
- height: 100%;
- margin: 0;
-}
-
-.contribute-grid .panel-body {
- padding: 10px;
-}
-
-.contribute-grid h2 {
- margin: 0 0 10px 0;
- padding: 0;
- display: flex;
- align-items: flex-start;
-}
-
-.contribute-grid .number {
- margin-right: 0.25em;
- font-size: 1.5em;
- line-height: 0.9;
-}
-</style>
-
-<div class="contribute-grid">
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="consensus"><span class="number">1</span><a
href="#consensus">Discuss</a></h2>
- <p>Create an Issue or mailing list discussion and reach consensus</p>
- <p><b>To request an issue, please note that it is not just a "please
assign it to me", you need to explain your understanding of the issue, and your
design, and if possible, you need to provide your POC code.</b></p>
- </div>
- </div>
- </div>
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="implement"><span class="number">2</span><a
href="#implement">Implement</a></h2>
- <p>Create the Pull Request and the approach agreed upon in the
issue.</p>
- <p><b>1.Only create the PR if you are assigned to the issue. 2.Please
associate an issue (if any), e.g. fix #123. 3.Please enable the actions of your
own clone project.</b></p>
- </div>
- </div>
- </div>
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="review"><span class="number">3</span><a
href="#review">Review</a></h2>
- <p>Work with the reviewer.</p><br />
- <p><b>1.Make sure no unrelated or unnecessary reformatting changes are
included. 2.Please ensure that the test passing. 3.Please don't resolve
conversation.</b></p>
- </div>
- </div>
- </div>
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="merge"><span class="number">4</span><a
href="#merge">Merge</a></h2>
- <p>A committer of Paimon checks if the contribution fulfills the
requirements and merges the code to the codebase.</p>
- </div>
- </div>
- </div>
-</div>
+
-## Code Review Guide
+[Open the contribution diagram at full
size](/img/project/contribution-workflow.svg).
+
+### Discuss {#consensus}
+
+Create an issue or mailing-list discussion that explains the problem and your
+proposed approach. Reach agreement before making a substantial change.
+
+When requesting assignment to an issue, explain your understanding, design,
+and, where useful, a proof of concept. An assignment request alone does not
+provide enough information. If you are working on an issue, wait until it is
+assigned to you before opening the pull request.
+
+### Implement {#implement}
+
+1. Implement the approach agreed in the discussion. Keep the change focused and
+ avoid unrelated refactoring or formatting.
+2. Add tests that exercise the changed behavior, including a regression test
+ for a bug fix. Update documentation for user-visible behavior.
+3. Follow the repository's [build
instructions](https://github.com/apache/paimon#building).
+ Run the relevant tests and formatting checks, and enable GitHub Actions in
+ your fork.
+4. Open a pull request describing the problem, resulting behavior, and
+ validation. Link the issue, if there is one; use `Fixes #123` when the pull
+ request resolves it.
+
+### Review {#review}
+
+Work with reviewers and explain how each concern was addressed. Keep tests
+passing as the change evolves. Leave review conversations open for reviewers
+to resolve after they check your response.
-Every review needs to check the following six aspects. **We encourage to check
these aspects in order, to avoid
-spending time on detailed code quality reviews when formal requirements are
not met or there is no consensus in
-the community to accept the change.**
+If implementation reveals a need to change the agreed approach, explain the
+new design before expanding the pull request.
-#### 1. Is the Contribution Well-Described?
+### Merge {#merge}
+
+A Paimon committer checks that the contribution meets the project requirements
+and merges it after review. A pull request with passing tests still needs
+review and agreement on its behavior.
+
+## Documentation changes
+
+The documentation source is in `docs/docs`, static images are in
+`docs/static/img`, and navigation is defined explicitly in `docs/sidebars.js`.
+When adding a page, add its document ID to the appropriate sidebar category.
+Use relative Markdown links between pages so that links remain within the
+selected documentation version.
+
+Prefer editable SVG for diagrams. Give each diagram descriptive alternative
+text and explain its essential steps in the page so that the information is
+also available without the image.
+
+From the repository root, install the documentation dependencies and build the
+site:
+
+```shell
+cd docs
+yarn install
+yarn build
+```
+
+The build runs the REST OpenAPI contract checks and compiles the documentation.
+Review the output for broken links and inspect the changed pages with
+`yarn serve`, including images and narrow-screen layouts. See the
+[documentation
README](https://github.com/apache/paimon/blob/master/docs/README.md)
+for local development and generated configuration tables.
+
+## Code Review Guide
-Check whether the contribution is sufficiently well-described to support a
good review. Trivial changes and fixes
-do not need a long description. If the implementation is exactly according to
a prior discussion on issue or the
-development mailing list, only a short reference to that discussion is needed.
+Review these four areas in order. Establish the purpose and agreement on the
+change before spending time on implementation details.
-If the implementation is different from the agreed approach in the consensus
discussion, a detailed description of
-the implementation is required for any further review of the contribution.
+### 1. Is the contribution well described?
-#### 2. Does the Contribution Need Attention from some Specific Committers?
+The description should make the problem and resulting behavior clear. Small
+fixes need only a short explanation. Link prior issue or mailing-list
+discussions when the implementation follows an agreed design; explain any
+departures from that design.
-Some changes require attention and approval from specific committers.
+### 2. Does it need attention from specific committers?
-If the pull request needs specific attention, one of the tagged
committers/contributors should give the final approval.
+Some changes need review from people familiar with the affected component or
+contract. When specific attention is required, one of the tagged committers
+or contributors should give the final approval.
-#### 3. Is the Overall Code Quality Good, Meeting Standard we Want to Maintain
in Paimon?
+### 3. Does the implementation meet Paimon's quality standards?
-- Does the code follow the right software engineering practices? Is the code
correct, robust, maintainable, testable?
-- Are the changes performance aware, when changing a performance sensitive
part?
-- Are the changes sufficiently covered by tests? Are the tests executing fast?
-- If dependencies have been changed, were the NOTICE files updated?
+- Check correctness, robustness, maintainability, and testability.
+- Consider performance when changing a performance-sensitive path.
+- Check that tests cover the changed behavior and run efficiently.
+- When dependencies change, check whether `LICENSE` or `NOTICE` needs updating.
-Code guidelines can be found in the [Flink Java Code Style and Quality
Guide](https://flink.apache.org/how-to-contribute/code-style-and-quality-java/).
+Refer to the [Flink Java Code Style and Quality
Guide](https://flink.apache.org/how-to-contribute/code-style-and-quality-java/)
+for code guidelines.
-#### 4. Are the documentation updated?
+### 4. Is the documentation current?
-If the pull request introduces a new feature, the feature should be documented.
+Document new features and changes to configuration, public APIs, or observable
+behavior. Check examples and links, and ensure that the documentation build
+passes.
## Become a Committer
-When you have made enough contributions, you can be nominated as Paimon's
Committer. See [Committer](./committer).
+Sustained code and community contributions can lead to nomination as a
+committer. See the [committer guide](./committer.md) for the nomination process
+and community expectations.
diff --git a/docs/docs/project/creating-a-release.md
b/docs/docs/project/creating-a-release.md
index 8e10c21fba..c8c15c41e2 100644
--- a/docs/docs/project/creating-a-release.md
+++ b/docs/docs/project/creating-a-release.md
@@ -37,77 +37,36 @@ after the vote.
:::
-## Release model
-
-The combined Paimon and PyPaimon release uses one shared version number. The
-Maven project version and `paimon-python/setup.py` version must be equal.
+## Before you start
-| Deliverable | Candidate | Published location |
-| --- | --- | --- |
-| Paimon source | `apache-paimon-PAIMON_VERSION-src.tgz`, `.asc`, `.sha512` |
ASF distribution |
-| Java convenience artifacts | Maven artifacts built in the JDK 8, 11, and 17
lanes | Apache Nexus staging, then Maven Central |
-| PyPaimon source | `pypaimon-PAIMON_VERSION.tar.gz`, `.asc`, `.sha512` | ASF
distribution |
-| Python convenience package | `pypaimon==PAIMON_VERSIONrcRC_NUMBER` for an RC
| TestPyPI, then `pypaimon==PAIMON_VERSION` on PyPI |
+Read the [release overview](./releases.md) for the artifact model and roles.
+Run the following steps in order; examples use `2.0.0` only to illustrate the
+variable names. Select the version and release branch agreed by the community.
-A combined release vote covers both signed source candidates. This guide does
-not define an independent PyPaimon release. Before releasing PyPaimon
-separately, the PMC must define a Python-only tag and workflow which do not
-depend on the Maven version or Java jobs, and must provide a signed source
-package which is independently sufficient to build and test the release.
+| Step | Ready to continue when |
+| --- | --- |
+| [Set up the RM environment](#one-time-rm-setup) | The signing key,
credentials, and service access are configured |
+| [Prepare the release](#prepare-the-release) | Versions agree and the signed
RC tag identifies a clean commit |
+| [Sign and stage Java
artifacts](#sign-and-stage-the-java-convenience-artifacts-locally) | One
complete Nexus repository is closed |
+| [Stage source candidates](#stage-the-source-candidates) | Both source
archives, signatures, and checksums are available |
+| [Call the vote](#call-the-vote) | All candidate URLs and provenance are in
the vote email |
+| [Publish after approval](./publishing-a-release.md) | The vote passed and
the approved candidate is unchanged |
-### Java build matrix
+## Release model
-The three Java lanes are different release targets, not interchangeable build
-JDKs:
+Paimon and PyPaimon use one shared version and one combined vote. See the
+[deliverables and Java build matrix](./releases.md#release-model).
-| JDK | Maven profiles and scope | Main artifacts |
-| --- | --- | --- |
-| 8 | `spark3,flink1` and the default reactor | Paimon core, Flink 1.x, Spark
3.x, Hive, filesystems, bundles, and other Java 8 artifacts |
-| 11 | `flink2` plus `paimon-iceberg` | Flink 2.x, `paimon-flink2-common`, and
Iceberg integration |
-| 17 | `spark4` | Spark 4.x and its Scala 2.13 common artifacts |
+### Java build matrix
-Each lane must use the matching JDK. Building everything on JDK 17 with a lower
-compiler target is not a substitute for running the JDK 8 and JDK 11 lanes.
+See the [JDK 8, 11, and 17 release targets](./releases.md#java-build-matrix).
## GitHub Actions release workflow
-The release process uses the
-[Release
workflow](https://github.com/apache/paimon/actions/workflows/release.yml)
-to package the JDK 8, JDK 11, and JDK 17 Java lanes and PyPaimon from every
-signed RC tag. The Java lanes are merged into one unsigned Maven repository
-image. The RM downloads that image, signs it, and stages it in Nexus. The RM
-also creates and signs the two ASF source archives locally from the same tag.
-The RM's GPG private key is never stored in GitHub Actions.
-
-The workflow has the following contract:
-
-| Job | Required behavior |
-| --- | --- |
-| Validation | Require an RC tag named `release-PAIMON_VERSION-rcN` or a final
tag named `release-PAIMON_VERSION`, where `PAIMON_VERSION` exactly equals the
root Maven `project.version` |
-| Java 8 | Use Temurin 8 to deploy the default reactor with Spark 3 and Flink
1 into a local Maven repository image |
-| Java 11 | Use Temurin 11 to deploy Flink 2 and Iceberg into a local Maven
repository image |
-| Java 17 | Use Temurin 17 to deploy Spark 4 into a local Maven repository
image |
-| Java repository | Require every deploy-enabled effective-POM project and its
POM, main JAR, and source JAR; retain Javadoc JARs where Maven produces them;
merge all three lanes; reject conflicting coordinates; then upload the complete
unsigned Maven repository image, checksums, manifests, and logs |
-| Python package | Build and validate the PyPaimon source distribution and
universal wheel, then upload them as workflow artifacts |
-| Python publish | Publish an RC to TestPyPI or a final tag to PyPI after
Python packaging passes, without waiting for Java packaging |
-
-Before packaging, every Java lane runs Maven Enforcer's
-`requireReleaseVersion` and `requireReleaseDeps` rules over its complete
reactor
-scope. The latter includes transitive dependencies. Any remaining
-`-SNAPSHOT` project, parent, direct dependency, or transitive dependency is a
-release blocker.
-
-The Java jobs run independently of the common validation and Python jobs. They
-use `-Dgpg.skip=true`, deploy only to runner-local file repositories, and never
-receive Nexus credentials or a GPG private key. The combined repository image
-contains POMs, main artifacts, source JARs, Javadoc JARs produced by Maven, and
-Maven-generated checksums. Scala-only and wrapper modules may not produce a
-Javadoc JAR. The image is the input to the RM's local signing and Nexus
-staging steps, not itself an ASF release. The Python RC job uses the
-`TEST_PYPI_API_TOKEN` repository Actions secret to publish
-`PAIMON_VERSIONrcRC_NUMBER` to TestPyPI. The final job uses the
-`PYPI_API_TOKEN` repository Actions secret to publish to PyPI. The release
-workflow passes only these two secrets to the reusable publishing workflow.
+The workflow packages Java artifacts and publishes Python candidates; the RM
+signs locally and stages the source and Java artifacts. See the
+[workflow contract](./releases.md#github-actions-release-workflow) before
running
+the commands below.
## One-time RM setup
@@ -471,93 +430,24 @@ If the vote finds a problem:
## Finalize an approved release
-### Create the final signed tag
-
-The final tag must point to exactly the approved RC commit:
+After recording a successful vote result, follow [Publishing a
Release](./publishing-a-release.md)
+with the approved candidate's variables and repository ID.
-```shell
-git tag -s "${RELEASE_TAG}" "refs/tags/${RC_REF}^{commit}" \
- -m "Release Apache Paimon ${PAIMON_VERSION}"
+### Create the final signed tag
-test "$(git rev-parse "refs/tags/${RC_REF}^{commit}")" = \
- "$(git rev-parse "refs/tags/${RELEASE_TAG}^{commit}")"
-git tag -v "${RELEASE_TAG}"
-git push origin "refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"
-```
+[Tag the approved RC
commit](./publishing-a-release.md#create-the-final-signed-tag).
### Promote the source releases
-Move, rather than copy or rebuild, both approved candidate directories:
-
-```shell
-svn mv -m "Release Apache Paimon ${PAIMON_VERSION}" \
-
"https://dist.apache.org/repos/dist/dev/paimon/paimon-${PAIMON_VERSION}-rc${RC_NUMBER}"
\
- "https://dist.apache.org/repos/dist/release/paimon/paimon-${PAIMON_VERSION}"
-
-svn mv -m "Release PyPaimon ${PAIMON_VERSION}" \
-
"https://dist.apache.org/repos/dist/dev/paimon/pypaimon-${PAIMON_VERSION}-rc${RC_NUMBER}"
\
-
"https://dist.apache.org/repos/dist/release/paimon/pypaimon-${PAIMON_VERSION}"
-```
+[Move the approved source directories to ASF dist
release](./publishing-a-release.md#promote-the-source-releases).
### Promote convenience artifacts
-1. In Nexus, confirm that the recorded Java staging repository is still closed
- and has the exact artifact tree approved by the vote.
-2. Release that exact closed repository to Maven Central. Do not upload or
- rebuild the Java artifacts again.
-3. Confirm that the final tag's PyPI publish job builds
- `pypaimon==PAIMON_VERSION` from the approved tag commit and does not change
- project source.
-4. Verify Maven Central and PyPI before announcing the release.
+[Release the closed Nexus repository and verify the final PyPI
package](./publishing-a-release.md#promote-convenience-artifacts).
### Publish and announce
-Create a GitHub release from `release-PAIMON_VERSION`, review the generated
-notes, and link both source releases.
-
-Before announcing the release, publish the versioned documentation and update
-the project website. Treat the documentation in `apache/paimon` and the project
-website in `apache/paimon-website` as two separate, required updates.
-
-1. In `apache/paimon`, publish documentation for `DOC_VERSION` from the release
- branch so that the published content matches the released code:
- - On `RELEASE_BRANCH`, update `docs/docusaurus.config.js` with the released
- `baseUrl`, `version`, `versionTitle`, `branch`, `editUrl`, `isStable`,
- `stableDocs`, `previousDocs`, and navbar version menu.
- - On `master`, set the next development version and update `stableDocs`,
- `previousDocs`, and the navbar version menu to include `DOC_VERSION` as
- the stable release.
- - Review `docs/docs/project/download.mdx` and any release-specific engine or
- compatibility information. The `@@VERSION@@`, `<Stable>`, and `<Unstable>`
- sections must render the released artifacts on the stable site.
- - Run `yarn build` from the `docs` directory for both configurations.
-2. In `apache/paimon-website`, update every public release entry point:
- - Add the Paimon and PyPaimon source archives, checksums, signatures, and
- current dependency examples to `community/docs/downloads.md`.
- - Create or update the appropriate
- `community/docs/releases/release-${DOC_VERSION}.md` release note. Its
- `version` front matter must equal `PAIMON_VERSION`, and its weight must
- place it correctly in the release list.
- - Add `DOC_VERSION` to the `versions` list in
- `src/app/components/header/header.component.ts`. If the menu keeps a fixed
- number of versions, remove the oldest entry.
- - Run `pnpm build` to parse the release metadata and build the website.
-3. After deployment, verify all public entry points before sending the
- announcement:
- - `https://paimon.apache.org/docs/${DOC_VERSION}/` serves the released docs
- and the version switcher identifies it as stable;
- - the homepage `DOCUMENT` menu includes `DOC_VERSION` on desktop and mobile;
- - `https://paimon.apache.org/downloads/` lists both signed source releases;
- - `https://paimon.apache.org/releases/${PAIMON_VERSION}` shows the release
- note.
-
-After ASF mirrors, Maven Central, PyPI, the versioned documentation, and the
-project website are all available, announce the release to
-`[email protected]` and `[email protected]` from an `@apache.org`
address.
-
-Remove superseded releases from the live ASF distribution area when required;
-they remain available from the
-[Apache archive](https://archive.apache.org/dist/paimon/).
+[Update documentation and the website before
announcing](./publishing-a-release.md#publish-and-announce).
See [Verifying a Release Candidate](./verifying-a-release-candidate.md) for the
voter checklist.
diff --git a/docs/docs/project/download.mdx b/docs/docs/project/download.mdx
index b361f7b84c..b2660f4856 100644
--- a/docs/docs/project/download.mdx
+++ b/docs/docs/project/download.mdx
@@ -1,6 +1,6 @@
---
title: "Download"
-sidebar_position: 2
+sidebar_position: 1
---
import Stable from '@site/src/components/Stable';
@@ -27,17 +27,48 @@ under the License.
# Download
-This documentation is a guide for downloading Paimon Jars.
+Choose artifacts for Paimon **@@VERSION@@** and the engine version you run.
+For released source archives, signatures, and checksums, use the
+[project downloads page](https://paimon.apache.org/downloads/). For the Python
+client, see [PyPaimon installation](../pypaimon/installation.md).
-## Engine Jars
+## Choose an artifact
+
+| You need to | Download | Installation guide |
+| --- | --- | --- |
+| Use Paimon from a query engine | The matching [engine JAR](#engine-jars) or
Trino plugin archive | [Flink](../flink/quick-start.mdx),
[Spark](../spark/quick-start.mdx), or your engine's integration guide |
+| Access object storage | The required [filesystem JAR](#filesystem-jars),
alongside the engine connector | [Filesystems](../maintenance/filesystems.mdx) |
+| Embed Paimon in a Java application | The [API bundle](#api-jars) | [Java
API](../program-api/java-api.mdx) |
+
+Match the engine version in the table, including the Scala binary version in
+Spark artifact names. Follow the integration guide for where to install the
+artifact; downloading a JAR alone does not configure a catalog or storage.
<Unstable>
+This is development documentation. The snapshot links below are intended for
+contributors testing unreleased changes. A snapshot repository can contain
+multiple timestamped builds; inspect the JAR's [manifest](#manifestmf) when
+reporting which build you tested. Use the project downloads page above for
+released versions.
+
+</Unstable>
+
+<Stable>
+The links below resolve convenience artifacts for this documentation version
+from Maven Central. Refer to the source download page above to verify the
+signed Apache release.
+
+</Stable>
+
+## Engine JARs
+
+<Unstable>
| Version | Jar
|
|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Flink 2.0 | Not yet released
|
+| Flink 2.x | For development builds, see [Build from
Source](../flink/installation.mdx#build-from-source). |
| Flink 1.20 |
[paimon-flink-1.20-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-flink-1.20/@@VERSION@@/)
|
| Flink 1.19 |
[paimon-flink-1.19-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-flink-1.19/@@VERSION@@/)
|
| Flink 1.18 |
[paimon-flink-1.18-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-flink-1.18/@@VERSION@@/)
|
@@ -54,17 +85,13 @@ This documentation is a guide for downloading Paimon Jars.
| Hive 2.3 |
[paimon-hive-connector-2.3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.3/@@VERSION@@/)
|
| Hive 2.2 |
[paimon-hive-connector-2.2-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.2/@@VERSION@@/)
|
| Hive 2.1 |
[paimon-hive-connector-2.1-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.1/@@VERSION@@/)
|
-| Hive 2.1-cdh-6.3 |
[paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.1-cdh-6.3/@@VERSION@@/)
| |
+| Hive 2.1-cdh-6.3 |
[paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.1-cdh-6.3/@@VERSION@@/)
|
| Trino 440 |
[paimon-trino-440-@@VERSION@@-plugin.tar.gz](https://repository.apache.org/content/repositories/snapshots/org/apache/paimon/paimon-trino-440/@@VERSION@@/)
|
-
-
</Unstable>
<Stable>
-
-
| Version | Jar
|
|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Flink 2.2 |
[paimon-flink-2.2-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-flink-2.2/@@VERSION@@/paimon-flink-2.2-@@VERSION@@.jar)
|
@@ -89,75 +116,59 @@ This documentation is a guide for downloading Paimon Jars.
| Hive 2.1-cdh-6.3 |
[paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-hive-connector-2.1-cdh-6.3/@@VERSION@@/paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar)
|
| Trino | [Download from
master](https://paimon.apache.org/docs/master/project/download/)
|
-
-
</Stable>
-## Filesystem Jars
+## Filesystem JARs
<Unstable>
-
-
| Version | Jar
|
|--------------|-----------------------------------------------------------------------------------------------------------------------------|
| paimon-oss |
[paimon-oss-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-oss/@@VERSION@@/)
|
| paimon-jindo |
[paimon-jindo-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-jindo/@@VERSION@@/)
|
| paimon-s3 |
[paimon-s3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-s3/@@VERSION@@/)
|
-
-
</Unstable>
<Stable>
-
-
| Version | Jar
|
|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| paimon-oss |
[paimon-oss-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-oss/@@VERSION@@/paimon-oss-@@VERSION@@.jar)
|
| paimon-jindo |
[paimon-jindo-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-jindo/@@VERSION@@/paimon-jindo-@@VERSION@@.jar)
|
| paimon-s3 |
[paimon-s3-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-s3/@@VERSION@@/paimon-s3-@@VERSION@@.jar)
|
-
-
</Stable>
-## API Jars
+## API JARs
<Unstable>
-
-
| Version | Jar
|
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| paimon-bundle |
[paimon-bundle-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-bundle/@@VERSION@@/)
|
-
-
</Unstable>
<Stable>
-
-
| Version | Jar
|
|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| paimon-bundle |
[paimon-bundle-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-bundle/@@VERSION@@/paimon-bundle-@@VERSION@@.jar)
|
-
-
</Stable>
-<Unstable>
-
+## Inspect a JAR manifest {#manifestmf}
+For a snapshot build, inspect `META-INF/MANIFEST.MF` inside the downloaded JAR:
-<h2>MANIFEST.MF</h2>
+```shell
+unzip -p /path/to/paimon.jar META-INF/MANIFEST.MF
+```
-For unstable version, you can find git commit id in jar:
+For example:
-```shell
+```text
Manifest-Version: 1.0
Implementation-Title: Paimon : Common
Implementation-Version: @@VERSION@@
@@ -172,8 +183,4 @@ Build-Jdk: 1.8.0_301
Specification-Version: @@VERSION@@
```
-The `SCM-Revision` git commit id.
-
-
-
-</Unstable>
+The `SCM-Revision` field identifies the Git commit used to build the JAR.
diff --git a/docs/docs/project/index.md b/docs/docs/project/index.md
index d4f76af4f8..fc1cfdae26 100644
--- a/docs/docs/project/index.md
+++ b/docs/docs/project/index.md
@@ -21,3 +21,38 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
+
+# Project
+
+Find the right Paimon package, contribute to the community, or help prepare and
+verify a release. Start with the task you want to complete.
+
+## Use Paimon
+
+| Task | Start here |
+| --- | --- |
+| Choose an engine connector, filesystem plugin, or Java API bundle |
[Download](./download.mdx) |
+| Install the Python client | [PyPaimon
installation](../pypaimon/installation.md) |
+| Report a possible vulnerability privately |
[Security](./security.md#reporting-security-issues) |
+| Understand Paimon's security boundaries | [Security
model](./security.md#security-model) |
+
+## Join the community
+
+| Task | Start here |
+| --- | --- |
+| Ask a question, report a bug, or improve documentation | [Ways to
contribute](./contributing.md#what-do-you-want-to-do) |
+| Prepare a code change | [Code contribution
guide](./contributing.md#code-contribution-guide) |
+| Review a pull request | [Code review
guide](./contributing.md#code-review-guide) |
+| Learn how committers are nominated and what is expected of them | [Committer
guide](./committer.md) |
+
+## Help release Paimon
+
+| Task | Start here |
+| --- | --- |
+| Understand the roles, artifacts, and release workflow | [Release
overview](./releases.md) |
+| Prepare and stage a candidate as Release Manager | [Creating a
release](./creating-a-release.md) |
+| Independently verify a candidate and report a vote | [Verifying a release
candidate](./verifying-a-release-candidate.md) |
+| Publish the approved artifacts, documentation, and announcement |
[Publishing a release](./publishing-a-release.md) |
+
+Release candidates are for community review. For released source packages, use
+the [project downloads page](https://paimon.apache.org/downloads/).
diff --git a/docs/docs/project/publishing-a-release.md
b/docs/docs/project/publishing-a-release.md
new file mode 100644
index 0000000000..dcc062a1ff
--- /dev/null
+++ b/docs/docs/project/publishing-a-release.md
@@ -0,0 +1,156 @@
+---
+title: "Publishing a Release"
+sidebar_position: 4
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Publishing a Release
+
+This guide is for the Release Manager after the combined Paimon and PyPaimon
+vote has passed and its result has been recorded. To prepare a candidate, start
+with [Creating a Release](./creating-a-release.md).
+
+## Confirm the approved inputs
+
+Use the exact candidate named in the successful vote. Keep the vote result,
+source URLs, closed Nexus repository ID, commit SHA, and workflow run URL
+available throughout publication.
+
+Set the same variables used when preparing that candidate. These values are
+examples; replace them with the approved release values:
+
+```shell
+PAIMON_VERSION="2.0.0"
+DOC_VERSION="2.0"
+RC_NUMBER="1"
+RELEASE_BRANCH="release-2.0"
+RC_REF="release-${PAIMON_VERSION}-rc${RC_NUMBER}"
+RELEASE_TAG="release-${PAIMON_VERSION}"
+```
+
+Run the tag commands in the release clone with the RM's signing key configured
+and the approved RC tag available locally. Use the same ASF distribution and
+Nexus access configured during [RM
setup](./creating-a-release.md#one-time-rm-setup).
+
+| Publish | Preserve |
+| --- | --- |
+| Final Git tag | The exact approved RC commit |
+| ASF source releases | The approved archives, signatures, and checksums |
+| Maven Central artifacts | The exact closed Nexus repository approved by the
vote |
+| PyPI package | The approved source commit, using the final Python version |
+| Documentation and website | Version labels, links, and examples matching the
release |
+
+## Create the final signed tag
+
+The final tag must point to exactly the approved RC commit:
+
+```shell
+git tag -s "${RELEASE_TAG}" "refs/tags/${RC_REF}^{commit}" \
+ -m "Release Apache Paimon ${PAIMON_VERSION}"
+
+test "$(git rev-parse "refs/tags/${RC_REF}^{commit}")" = \
+ "$(git rev-parse "refs/tags/${RELEASE_TAG}^{commit}")"
+git tag -v "${RELEASE_TAG}"
+git push origin "refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"
+```
+
+## Promote the source releases
+
+Move, rather than copy or rebuild, both approved candidate directories:
+
+```shell
+svn mv -m "Release Apache Paimon ${PAIMON_VERSION}" \
+
"https://dist.apache.org/repos/dist/dev/paimon/paimon-${PAIMON_VERSION}-rc${RC_NUMBER}"
\
+ "https://dist.apache.org/repos/dist/release/paimon/paimon-${PAIMON_VERSION}"
+
+svn mv -m "Release PyPaimon ${PAIMON_VERSION}" \
+
"https://dist.apache.org/repos/dist/dev/paimon/pypaimon-${PAIMON_VERSION}-rc${RC_NUMBER}"
\
+
"https://dist.apache.org/repos/dist/release/paimon/pypaimon-${PAIMON_VERSION}"
+```
+
+## Promote convenience artifacts
+
+1. In Nexus, confirm that the recorded Java staging repository is still closed
+ and has the exact artifact tree approved by the vote.
+2. Release that exact closed repository to Maven Central. Do not upload or
+ rebuild the Java artifacts again.
+3. Confirm that the final tag's PyPI publish job builds
+ `pypaimon==PAIMON_VERSION` from the approved tag commit and does not change
+ project source.
+4. Verify Maven Central and PyPI before announcing the release.
+
+## Publish and announce
+
+Create a GitHub release from `release-PAIMON_VERSION`, review the generated
+notes, and link both source releases.
+
+Before announcing the release, publish the versioned documentation and update
+the project website. Treat the documentation in `apache/paimon` and the project
+website in `apache/paimon-website` as two separate, required updates.
+
+1. In `apache/paimon`, publish documentation for `DOC_VERSION` from the release
+ branch so that the published content matches the released code:
+ - On `RELEASE_BRANCH`, update `docs/docusaurus.config.js` with the released
+ `baseUrl`, `version`, `versionTitle`, `branch`, `editUrl`, `isStable`,
+ `stableDocs`, `previousDocs`, and navbar version menu.
+ - On `master`, set the next development version and update `stableDocs`,
+ `previousDocs`, and the navbar version menu to include `DOC_VERSION` as
+ the stable release.
+ - Review `docs/docs/project/download.mdx` and any release-specific engine or
+ compatibility information. The `@@VERSION@@`, `<Stable>`, and `<Unstable>`
+ sections must render the released artifacts on the stable site.
+ - Run `yarn build` from the `docs` directory for both configurations.
+2. In `apache/paimon-website`, update every public release entry point:
+ - Add the Paimon and PyPaimon source archives, checksums, signatures, and
+ current dependency examples to `community/docs/downloads.md`.
+ - Create or update the appropriate
+ `community/docs/releases/release-${DOC_VERSION}.md` release note. Its
+ `version` front matter must equal `PAIMON_VERSION`, and its weight must
+ place it correctly in the release list.
+ - Add `DOC_VERSION` to the `versions` list in
+ `src/app/components/header/header.component.ts`. If the menu keeps a fixed
+ number of versions, remove the oldest entry.
+ - Run `pnpm build` to parse the release metadata and build the website.
+3. After deployment, verify all public entry points before sending the
+ announcement:
+ - `https://paimon.apache.org/docs/${DOC_VERSION}/` serves the released docs
+ and the version switcher identifies it as stable;
+ - the homepage `DOCUMENT` menu includes `DOC_VERSION` on desktop and mobile;
+ - `https://paimon.apache.org/downloads/` lists both signed source releases;
+ - `https://paimon.apache.org/releases/${PAIMON_VERSION}` shows the release
+ note.
+
+After ASF mirrors, Maven Central, PyPI, the versioned documentation, and the
+project website are all available, announce the release to
+`[email protected]` and `[email protected]` from an `@apache.org`
address.
+
+Remove superseded releases from the live ASF distribution area when required;
+they remain available from the
+[Apache archive](https://archive.apache.org/dist/paimon/).
+
+## Completion checklist
+
+- The final signed tag resolves to the approved RC commit.
+- Both source releases and their signatures and checksums are available.
+- Maven Central and PyPI expose the intended release versions.
+- Versioned documentation, download links, and release notes are published.
+- The announcement links the public release, and superseded candidates have
+ been handled without replacing the artifacts reviewed in the vote.
diff --git a/docs/docs/project/releases.md b/docs/docs/project/releases.md
new file mode 100644
index 0000000000..3e23b79fb7
--- /dev/null
+++ b/docs/docs/project/releases.md
@@ -0,0 +1,159 @@
+---
+title: "Release Overview"
+sidebar_position: 1
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Release Overview
+
+Paimon and PyPaimon share a release version and a community vote. This page
+explains what is released and who does each part of the work. Use the linked
+guides for commands and verification steps.
+
+| Your task | Guide | Result |
+| --- | --- | --- |
+| Manage a release candidate (RC) | [Creating a
release](./creating-a-release.md) | Signed source archives, a closed Java
staging repository, and a vote thread |
+| Review a candidate | [Verifying a release
candidate](./verifying-a-release-candidate.md) | An independent vote with the
checks and environment recorded |
+| Publish an approved candidate | [Publishing a
release](./publishing-a-release.md) | Public artifacts, documentation, release
notes, and announcement |
+
+## Release lifecycle
+
+
+
+[Open the lifecycle diagram at full size](/img/project/release-lifecycle.svg).
+
+1. The Release Manager (RM) agrees the scope with the community and creates a
+ signed RC tag.
+2. GitHub Actions packages convenience artifacts. The RM signs and stages the
+ Java artifacts and both source archives from the same tag.
+3. Community members independently verify the candidate and vote. The RM
+ records the result.
+4. After approval, the RM publishes the approved artifacts and updates the
+ documentation and website before announcing the release. A failed
+ candidate needs a new RC number and a new vote.
+
+The process follows the [ASF Release
Policy](https://www.apache.org/legal/release-policy.html)
+and [ASF Release Distribution
Policy](https://infra.apache.org/release-distribution.html).
+
+:::warning Preserve the approved candidate
+
+The signed source archives are the Apache releases. Maven and PyPI packages
+are convenience artifacts. Promote the source archives and closed Java
+repository approved by the vote; do not rebuild or replace them. The final
+PyPI package is built from the approved commit with the final version.
+
+:::
+
+## Release model
+
+The combined Paimon and PyPaimon release uses one shared version number. The
+Maven project version and `paimon-python/setup.py` version must be equal.
+
+| Deliverable | Candidate | Published location |
+| --- | --- | --- |
+| Paimon source | `apache-paimon-PAIMON_VERSION-src.tgz`, `.asc`, `.sha512` |
ASF distribution |
+| Java convenience artifacts | Maven artifacts built in the JDK 8, 11, and 17
lanes | Apache Nexus staging, then Maven Central |
+| PyPaimon source | `pypaimon-PAIMON_VERSION.tar.gz`, `.asc`, `.sha512` | ASF
distribution |
+| Python convenience package | `pypaimon==PAIMON_VERSIONrcRC_NUMBER` for an RC
| TestPyPI, then `pypaimon==PAIMON_VERSION` on PyPI |
+
+A combined release vote covers both signed source candidates. This guide does
+not define an independent PyPaimon release. Before releasing PyPaimon
+separately, the PMC must define a Python-only tag and workflow which do not
+depend on the Maven version or Java jobs, and must provide a signed source
+package which is independently sufficient to build and test the release.
+
+### Java build matrix
+
+The three Java lanes are different release targets, not interchangeable build
+JDKs:
+
+| JDK | Maven profiles and scope | Main artifacts |
+| --- | --- | --- |
+| 8 | `spark3,flink1` and the default reactor | Paimon core, Flink 1.x, Spark
3.x, Hive, filesystems, bundles, and other Java 8 artifacts |
+| 11 | `flink2` plus `paimon-iceberg` | Flink 2.x, `paimon-flink2-common`, and
Iceberg integration |
+| 17 | `spark4` | Spark 4.x and its Scala 2.13 common artifacts |
+
+Each lane must use the matching JDK. Building everything on JDK 17 with a lower
+compiler target is not a substitute for running the JDK 8 and JDK 11 lanes.
+
+## GitHub Actions release workflow
+
+The release process uses the
+[Release
workflow](https://github.com/apache/paimon/actions/workflows/release.yml)
+to package the JDK 8, JDK 11, and JDK 17 Java lanes and PyPaimon from every
+signed RC tag. The Java lanes are merged into one unsigned Maven repository
+image. The RM downloads that image, signs it, and stages it in Nexus. The RM
+also creates and signs the two ASF source archives locally from the same tag.
+The RM's GPG private key is never stored in GitHub Actions.
+
+The workflow has the following contract:
+
+| Job | Required behavior |
+| --- | --- |
+| Validation | Require an RC tag named `release-PAIMON_VERSION-rcN` or a final
tag named `release-PAIMON_VERSION`, where `PAIMON_VERSION` exactly equals the
root Maven `project.version` |
+| Java 8 | Use Temurin 8 to deploy the default reactor with Spark 3 and Flink
1 into a local Maven repository image |
+| Java 11 | Use Temurin 11 to deploy Flink 2 and Iceberg into a local Maven
repository image |
+| Java 17 | Use Temurin 17 to deploy Spark 4 into a local Maven repository
image |
+| Java repository | Require every deploy-enabled effective-POM project and its
POM, main JAR, and source JAR; retain Javadoc JARs where Maven produces them;
merge all three lanes; reject conflicting coordinates; then upload the complete
unsigned Maven repository image, checksums, manifests, and logs |
+| Python package | Build and validate the PyPaimon source distribution and
universal wheel, then upload them as workflow artifacts |
+| Python publish | Publish an RC to TestPyPI or a final tag to PyPI after
Python packaging passes, without waiting for Java packaging |
+
+Before packaging, every Java lane runs Maven Enforcer's
+`requireReleaseVersion` and `requireReleaseDeps` rules over its complete
reactor
+scope. The latter includes transitive dependencies. Any remaining
+`-SNAPSHOT` project, parent, direct dependency, or transitive dependency is a
+release blocker.
+
+The Java jobs run independently of the common validation and Python jobs. They
+use `-Dgpg.skip=true`, deploy only to runner-local file repositories, and never
+receive Nexus credentials or a GPG private key. The combined repository image
+contains POMs, main artifacts, source JARs, Javadoc JARs produced by Maven, and
+Maven-generated checksums. Scala-only and wrapper modules may not produce a
+Javadoc JAR. The image is the input to the RM's local signing and Nexus
+staging steps, not itself an ASF release. The Python RC job uses the
+`TEST_PYPI_API_TOKEN` repository Actions secret to publish
+`PAIMON_VERSIONrcRC_NUMBER` to TestPyPI. The final job uses the
+`PYPI_API_TOKEN` repository Actions secret to publish to PyPI. The release
+workflow passes only these two secrets to the reusable publishing workflow.
+
+## Artifact flow
+
+
+
+[Open the artifact diagram at full size](/img/project/release-artifacts.svg).
+
+Source and Java publication preserve the approved bytes. Python publication
+builds the final PyPI version from the final tag at the approved RC commit.
+All three paths must be checked before the release announcement.
+
+## Responsibilities and handoffs
+
+| Owner | Responsibility | Evidence to hand off |
+| --- | --- | --- |
+| RM | Review relevant CI results and prepare an immutable candidate | Signed
tag, commit SHA, and release versions |
+| GitHub Actions | Package Java lanes and Python artifacts | Run URL,
manifests, checksums, logs, and TestPyPI version |
+| RM | Sign locally and stage the candidate | Both source URLs, signing-key
fingerprint, and closed Nexus repository URL |
+| Voters | Independently inspect, build, and test the source candidate | Vote
with actual checks, platforms, tool versions, and any failures |
+| RM | Tally the vote and publish after approval | Vote result, final tag,
public downloads, and updated documentation |
+
+The Java packaging lanes do not run the full test matrix. The RM reviews
+relevant CI results before calling the vote, and voters report their own
+source build and test scope. Packaging success alone is not release approval.
diff --git a/docs/docs/project/security.md b/docs/docs/project/security.md
index 134569d19d..e8dc525def 100644
--- a/docs/docs/project/security.md
+++ b/docs/docs/project/security.md
@@ -1,6 +1,6 @@
---
title: "Security"
-sidebar_position: 4
+sidebar_position: 2
---
<!--
@@ -24,6 +24,10 @@ under the License.
# Security
+Use this page to report a possible vulnerability and understand which trust
+boundaries Paimon owns. For ordinary bugs, use the
+[contribution guide](./contributing.md#what-do-you-want-to-do).
+
## Reporting Security Issues
The Apache Paimon Project uses the standard process outlined by the
@@ -34,11 +38,13 @@ Note that vulnerabilities should not be publicly disclosed
until the project
has responded.
To report a possible security vulnerability, please email
-**[[email protected]](mailto:[email protected])**.
+**[[email protected]](mailto:[email protected])**. Include the affected
+Paimon version, deployment context, steps to reproduce, and the observed
+impact. Remove live credentials from examples and logs.
## Security Model
-Apache Paimon is a data lake platform and a set of libraries and integrations
+Apache Paimon is a data lake platform and a set of libraries and integrations
used inside larger systems such as catalogs, query engines, and services.
In most deployments, the primary trust and authorization boundaries are
diff --git a/docs/docs/project/verifying-a-release-candidate.md
b/docs/docs/project/verifying-a-release-candidate.md
index d2ea99b6b3..c0a5b55933 100644
--- a/docs/docs/project/verifying-a-release-candidate.md
+++ b/docs/docs/project/verifying-a-release-candidate.md
@@ -29,6 +29,29 @@ PyPaimon source archives are the release. Maven, TestPyPI,
and GitHub Actions
checks supplement source verification but do not replace it.
Report only the checks, platforms, and tool versions that you actually used.
+For roles and artifact relationships, see the [release
overview](./releases.md).
+
+## Verification checklist
+
+Work through the checks in order, using the candidate named in the vote email.
+Keep notes for the [vote report](#report-your-vote).
+
+| Check | Evidence to record |
+| --- | --- |
+| [Collect inputs](#collect-the-candidate-inputs) | Version, RC number, source
URLs, tag, commit, workflow, and staging URLs |
+| [Verify signatures and checksums](#verify-signatures-and-checksums) |
Signing-key fingerprint and successful checks for both archives |
+| [Verify Git provenance](#verify-git-provenance) | Signed tag resolves to the
announced commit |
+| [Inspect archives](#inspect-the-source-archives) | Expected source contents,
versions, licenses, and legal reports |
+| [Build Java from source](#build-java-from-the-source-archive) | JDK, Maven,
platform, build scope, and test or smoke-test result |
+| [Inspect Java staging](#verify-the-java-staging-repository) | Closed
repository, complete artifacts, and representative runtime checks |
+| [Build and test PyPaimon](#build-and-test-pypaimon-from-source) | Python
versions, package contents, and actual test results |
+| [Check TestPyPI](#verify-the-testpypi-candidate) | Exact RC installation and
representative read/write result |
+| [Review workflow evidence](#review-github-actions-evidence) | Matching
provenance, package manifests, and successful packaging lanes |
+
+For a binding `+1`, download all signed source packages, verify them, compile
+them, and test the result on your own platform, as required by the
+[ASF Release
Policy](https://www.apache.org/legal/release-policy.html#release-approval).
+The optional packaging commands below skip tests and do not replace this work.
## Collect the candidate inputs
@@ -319,8 +342,9 @@ test suite for the PyPaimon candidate is supplied in the
signed Paimon source
archive; the PyPaimon source distribution must not be used by itself for an
independent release. Run the tests from
`paimon-PAIMON_VERSION/paimon-python` on as many supported Python versions as
-your environment allows. The project CI selects Python 3.6, 3.7, 3.10, and
-3.11 for its main compatibility lanes:
+your environment allows. Use the Python matrix in the candidate's
+`.github/workflows/paimon-python-checks.yml` to select relevant versions rather
+than assuming that a matrix from another release applies:
```shell
(
diff --git a/docs/sidebars.js b/docs/sidebars.js
index eb32e6c79f..9c9f11a299 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -671,11 +671,25 @@ const sidebars = {
},
"items": [
"project/download",
- "project/creating-a-release",
- "project/verifying-a-release-candidate",
- "project/contributing",
- "project/committer",
- "project/security"
+ "project/security",
+ {
+ type: "category",
+ "label": "Community",
+ "items": [
+ "project/contributing",
+ "project/committer"
+ ]
+ },
+ {
+ type: "category",
+ "label": "Releases",
+ "link": { type: "doc", "id": "project/releases" },
+ "items": [
+ "project/creating-a-release",
+ "project/verifying-a-release-candidate",
+ "project/publishing-a-release"
+ ]
+ }
]
},
{
diff --git a/docs/static/img/project/contribution-workflow.svg
b/docs/static/img/project/contribution-workflow.svg
new file mode 100644
index 0000000000..86cbc82fae
--- /dev/null
+++ b/docs/static/img/project/contribution-workflow.svg
@@ -0,0 +1,55 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="960" height="436" viewBox="0 0
960 436" role="img" aria-labelledby="title desc">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<title id="title">From an idea to a merged contribution</title>
+<desc id="desc">Discuss the problem and agree on an approach. Implement a
focused change with tests and documentation. Address review feedback; reviewers
resolve conversations. A committer merges after requirements are met. Review
feedback can lead back to implementation.</desc>
+<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7"
markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z"
fill="#526277"/></marker></defs>
+<g font-family="Arial, Helvetica, sans-serif">
+<rect x="1" y="1" width="958" height="434" rx="12" fill="#ffffff"
stroke="#d7dfeb" stroke-width="1.5"/>
+<text x="28" y="44" font-size="27" fill="#172b4d" font-weight="700"
text-anchor="start">From an idea to a merged contribution</text>
+<text x="28" y="76" font-size="18" fill="#526277" font-weight="400"
text-anchor="start">Agree on the problem, keep the change focused, and work
with reviewers.</text>
+<rect x="28" y="117" width="199" height="153" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="127.5" y="150" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">1 Discuss</text>
+<text x="127.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Explain the use case</text>
+<text x="127.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Agree on an approach</text>
+<text x="127.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Request assignment</text>
+<rect x="263" y="117" width="199" height="153" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="362.5" y="150" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">2 Implement</text>
+<text x="362.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Follow the agreement</text>
+<text x="362.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Add tests and docs</text>
+<text x="362.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Open a focused PR</text>
+<rect x="498" y="117" width="199" height="153" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="597.5" y="150" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">3 Review</text>
+<text x="597.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Address feedback</text>
+<text x="597.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Keep checks passing</text>
+<text x="597.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Reviewer resolves</text>
+<rect x="733" y="117" width="199" height="153" rx="8" fill="#e8f7f2"
stroke="#087f6e" stroke-width="1.5"/>
+<text x="832.5" y="150" font-size="21" fill="#087f6e" font-weight="700"
text-anchor="middle">4 Merge</text>
+<text x="832.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Committer checks</text>
+<text x="832.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">the requirements</text>
+<text x="832.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">and merges the PR</text>
+<path d="M 227 192 H 263" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 462 192 H 498" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 697 192 H 733" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 597 270 V 315 H 362 V 270" fill="none" stroke="#526277"
stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow)"/>
+<text x="480" y="343" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Revise the change as review progresses</text>
+<rect x="28" y="370" width="904" height="42" rx="8" fill="#f5f7fb"
stroke="#c6d1df" stroke-width="1.5"/>
+<text x="480" y="397" font-size="18" fill="#172b4d" font-weight="400"
text-anchor="middle">Small fixes, documentation, testing, and community support
all count.</text>
+</g>
+</svg>
diff --git a/docs/static/img/project/release-artifacts.svg
b/docs/static/img/project/release-artifacts.svg
new file mode 100644
index 0000000000..1b052ecced
--- /dev/null
+++ b/docs/static/img/project/release-artifacts.svg
@@ -0,0 +1,83 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="960" height="718" viewBox="0 0
960 718" role="img" aria-labelledby="title desc">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<title id="title">Follow each artifact from the same signed RC tag</title>
+<desc id="desc">A signed RC tag identifies one commit. The Release Manager
creates and signs the Paimon and PyPaimon source archives locally, stages them
in ASF dist dev, and promotes them after approval. GitHub Actions packages Java
on JDK 8, 11, and 17; the Release Manager signs the merged repository and
closes it in Nexus, then promotes it to Maven Central after approval. Python
validation and packaging publish the RC to TestPyPI independently of Java.
After approval, the final signed [...]
+<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7"
markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z"
fill="#526277"/></marker></defs>
+<g font-family="Arial, Helvetica, sans-serif">
+<rect x="1" y="1" width="958" height="716" rx="12" fill="#ffffff"
stroke="#d7dfeb" stroke-width="1.5"/>
+<text x="28" y="44" font-size="27" fill="#172b4d" font-weight="700"
text-anchor="start">Follow each artifact from the same signed RC tag</text>
+<text x="28" y="76" font-size="18" fill="#526277" font-weight="400"
text-anchor="start">Sources define the Apache release; Java and Python packages
are convenience artifacts.</text>
+<rect x="28" y="101" width="904" height="52" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="480" y="133" font-size="19" fill="#2463b4" font-weight="700"
text-anchor="middle">Signed RC tag → one recorded commit and matching Paimon
/ PyPaimon versions</text>
+<text x="192" y="192" font-size="16" fill="#172b4d" font-weight="700"
text-anchor="middle">BUILD AND SIGN</text>
+<text x="514" y="192" font-size="16" fill="#172b4d" font-weight="700"
text-anchor="middle">CANDIDATE FOR REVIEW</text>
+<text x="820" y="192" font-size="16" fill="#087f6e" font-weight="700"
text-anchor="middle">AFTER VOTE APPROVAL</text>
+<path d="M 665 178 V 653" fill="none" stroke="#526277" stroke-width="2"
stroke-dasharray="6 5"/>
+<rect x="28" y="213" width="328" height="114" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="192.0" y="246" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">Source archives · RM</text>
+<text x="192.0" y="276" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Build both sources locally</text>
+<text x="192.0" y="301" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Sign and checksum each archive</text>
+<rect x="404" y="213" width="220" height="114" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="514.0" y="246" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">ASF dist dev</text>
+<text x="514.0" y="276" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Paimon + PyPaimon</text>
+<text x="514.0" y="301" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Signed source archives</text>
+<rect x="692" y="213" width="240" height="114" rx="8" fill="#e8f7f2"
stroke="#087f6e" stroke-width="1.5"/>
+<text x="812.0" y="246" font-size="21" fill="#087f6e" font-weight="700"
text-anchor="middle">ASF dist release</text>
+<text x="812.0" y="276" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Move approved directories</text>
+<text x="812.0" y="301" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Preserve every file</text>
+<path d="M 356 270 H 404" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 624 270 H 692" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<rect x="28" y="355" width="328" height="137" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="192.0" y="388" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">Java · Actions, then RM</text>
+<text x="192.0" y="418" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Package on JDK 8 / 11 / 17</text>
+<text x="192.0" y="443" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Merge the unsigned repository</text>
+<text x="192.0" y="468" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">RM signs and stages locally</text>
+<rect x="404" y="355" width="220" height="137" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="514.0" y="388" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">Closed Nexus repo</text>
+<text x="514.0" y="418" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">One complete repository</text>
+<text x="514.0" y="443" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Signatures + checksums</text>
+<text x="514.0" y="468" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Same RC commit</text>
+<rect x="692" y="355" width="240" height="137" rx="8" fill="#e8f7f2"
stroke="#087f6e" stroke-width="1.5"/>
+<text x="812.0" y="388" font-size="21" fill="#087f6e" font-weight="700"
text-anchor="middle">Maven Central</text>
+<text x="812.0" y="418" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Release the approved repo</text>
+<text x="812.0" y="443" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Preserve every artifact</text>
+<text x="812.0" y="468" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">No Java rebuild</text>
+<path d="M 356 423 H 404" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 624 423 H 692" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<rect x="28" y="520" width="328" height="137" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="192.0" y="553" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">Python · Actions</text>
+<text x="192.0" y="583" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Validate and package</text>
+<text x="192.0" y="608" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Publish after Python succeeds</text>
+<text x="192.0" y="633" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Runs independently of Java</text>
+<rect x="404" y="520" width="220" height="137" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="514.0" y="553" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">TestPyPI</text>
+<text x="514.0" y="583" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Candidate version</text>
+<text x="514.0" y="608" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">VERSIONrcN</text>
+<text x="514.0" y="633" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">For community testing</text>
+<rect x="692" y="520" width="240" height="137" rx="8" fill="#e8f7f2"
stroke="#087f6e" stroke-width="1.5"/>
+<text x="812.0" y="553" font-size="21" fill="#087f6e" font-weight="700"
text-anchor="middle">PyPI</text>
+<text x="812.0" y="583" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Final tag at RC commit</text>
+<text x="812.0" y="608" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Build the final VERSION</text>
+<text x="812.0" y="633" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Same approved source</text>
+<path d="M 356 588 H 404" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 624 588 H 692" fill="none" stroke="#526277" stroke-width="2"
stroke-dasharray="6 5" marker-end="url(#arrow)"/>
+<text x="28" y="690" font-size="17" fill="#526277" font-weight="400"
text-anchor="start">Solid arrows: stage / promote artifacts. Dashed arrow:
build the final Python version.</text>
+</g>
+</svg>
diff --git a/docs/static/img/project/release-lifecycle.svg
b/docs/static/img/project/release-lifecycle.svg
new file mode 100644
index 0000000000..9e9d3551f3
--- /dev/null
+++ b/docs/static/img/project/release-lifecycle.svg
@@ -0,0 +1,55 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="960" height="448" viewBox="0 0
960 448" role="img" aria-labelledby="title desc">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<title id="title">A candidate becomes a release after approval</title>
+<desc id="desc">The Release Manager prepares an immutable signed RC tag,
stages source and convenience artifacts, and calls the community vote. After
verification and approval, the approved candidate is published. Problems
require fixes, a new RC number, and a new vote.</desc>
+<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7"
markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z"
fill="#526277"/></marker></defs>
+<g font-family="Arial, Helvetica, sans-serif">
+<rect x="1" y="1" width="958" height="446" rx="12" fill="#ffffff"
stroke="#d7dfeb" stroke-width="1.5"/>
+<text x="28" y="44" font-size="27" fill="#172b4d" font-weight="700"
text-anchor="start">A candidate becomes a release after approval</text>
+<text x="28" y="76" font-size="18" fill="#526277" font-weight="400"
text-anchor="start">One shared Paimon / PyPaimon version; one immutable
candidate per vote.</text>
+<rect x="28" y="117" width="199" height="153" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="127.5" y="150" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">1 Prepare</text>
+<text x="127.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Agree on the scope</text>
+<text x="127.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Set both versions</text>
+<text x="127.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Sign the RC tag</text>
+<rect x="263" y="117" width="199" height="153" rx="8" fill="#eaf2ff"
stroke="#2463b4" stroke-width="1.5"/>
+<text x="362.5" y="150" font-size="21" fill="#2463b4" font-weight="700"
text-anchor="middle">2 Stage</text>
+<text x="362.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Sign source archives</text>
+<text x="362.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Close Java staging</text>
+<text x="362.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Publish to TestPyPI</text>
+<rect x="498" y="117" width="199" height="153" rx="8" fill="#fff6e5"
stroke="#946200" stroke-width="1.5"/>
+<text x="597.5" y="150" font-size="21" fill="#946200" font-weight="700"
text-anchor="middle">3 Verify + vote</text>
+<text x="597.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Check the candidate</text>
+<text x="597.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Build and test source</text>
+<text x="597.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Record the result</text>
+<rect x="733" y="117" width="199" height="153" rx="8" fill="#e8f7f2"
stroke="#087f6e" stroke-width="1.5"/>
+<text x="832.5" y="150" font-size="21" fill="#087f6e" font-weight="700"
text-anchor="middle">4 Publish</text>
+<text x="832.5" y="180" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Promote artifacts</text>
+<text x="832.5" y="205" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Verify final packages</text>
+<text x="832.5" y="230" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Docs, then announce</text>
+<path d="M 227 192 H 263" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 462 192 H 498" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 697 192 H 733" fill="none" stroke="#526277" stroke-width="2"
marker-end="url(#arrow)"/>
+<path d="M 597 270 V 318 H 127 V 270" fill="none" stroke="#526277"
stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow)"/>
+<text x="362" y="347" font-size="18" fill="#526277" font-weight="400"
text-anchor="middle">Problem found: fix it, increment RC, and vote again</text>
+<rect x="28" y="378" width="904" height="42" rx="8" fill="#f5f7fb"
stroke="#c6d1df" stroke-width="1.5"/>
+<text x="480" y="405" font-size="18" fill="#172b4d" font-weight="400"
text-anchor="middle">Keep the approved source archives, Java repository, and
commit unchanged.</text>
+</g>
+</svg>