feat: add react-markdown dependency and update README with release process

This commit is contained in:
Usman Baig
2026-02-09 17:17:21 +01:00
parent fe6530b464
commit 72e891f856
8 changed files with 1336 additions and 2 deletions

21
CHANGELOG.md Normal file
View File

@@ -0,0 +1,21 @@
# Changelog
All notable changes to Pulse (frontend and product) are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and Pulse uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) with a **0.x.y** version scheme while in initial development. The leading `0` indicates that the public API and behaviour may change until we release **1.0.0**.
## [Unreleased]
- No unreleased changes yet; add items here as you work toward the next release.
## [0.1.0] - 2026-02-09
### Added
- Initial changelog and release process (PULSE-28).
- Release documentation in `docs/releasing.md` and optional changelog check script.
---
[Unreleased]: https://github.com/ciphera-net/pulse/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/ciphera-net/pulse/releases/tag/v0.1.0

View File

@@ -60,6 +60,10 @@ npm run build
npm start
```
## Releasing
Changelog and release process (who updates it, when, how to tag, deploy) are documented in [docs/releasing.md](docs/releasing.md). Versions use **0.x.y** while in initial development; the single product changelog is [CHANGELOG.md](CHANGELOG.md).
## Design System
The frontend follows the Ciphera design language:

46
app/changelog/page.tsx Normal file
View File

@@ -0,0 +1,46 @@
import fs from 'fs'
import path from 'path'
import ReactMarkdown from 'react-markdown'
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Changelog - Pulse',
description: 'Release history and notable changes for Pulse, privacy-first web analytics.',
}
/**
* Reads CHANGELOG.md from the project root and renders it on the /changelog page.
* Content is loaded at build time; redeploy to show new releases.
*/
export default function ChangelogPage() {
const changelogPath = path.join(process.cwd(), 'CHANGELOG.md')
const content = fs.readFileSync(changelogPath, 'utf-8')
return (
<div className="mx-auto max-w-3xl px-4 sm:px-6 py-8">
<h1 className="text-3xl font-bold text-neutral-900 dark:text-white mb-2">
Changelog
</h1>
<p className="text-neutral-600 dark:text-neutral-400 mb-8 text-sm">
Release history and notable changes. We use{' '}
<a
href="https://keepachangelog.com/en/1.1.0/"
target="_blank"
rel="noopener noreferrer"
className="text-brand-orange hover:underline"
>
Keep a Changelog
</a>{' '}
and <strong>0.x.y</strong> versioning while in initial development.
</p>
<article
className="prose prose-neutral dark:prose-invert max-w-none
prose-headings:font-semibold prose-headings:tracking-tight
prose-a:text-brand-orange prose-a:no-underline hover:prose-a:underline
prose-ul:my-4 prose-li:my-0.5"
>
<ReactMarkdown>{content}</ReactMarkdown>
</article>
</div>
)
}

View File

@@ -26,6 +26,7 @@ const footerLinks = {
{ name: 'Contact', href: 'https://ciphera.net/contact', external: true },
],
resources: [
{ name: 'Changelog', href: '/changelog', external: false },
{ name: 'Installation', href: '/installation', external: false },
{ name: 'Integrations', href: '/integrations', external: false },
{ name: 'Documentation', href: 'https://docs.ciphera.net', external: true },
@@ -55,6 +56,9 @@ export function Footer({ LinkComponent = Link, appName = 'Pulse', isAuthenticate
<Component href="/about" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
Why {appName}
</Component>
<Component href="/changelog" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
Changelog
</Component>
<Component href="/pricing" className="hover:text-brand-orange transition-colors focus:outline-none focus:ring-2 focus:ring-brand-orange focus:rounded">
Pricing
</Component>

54
docs/releasing.md Normal file
View File

@@ -0,0 +1,54 @@
# Releasing Pulse
This document describes how to cut a release for Pulse (changelog, tagging, and deploy). It applies to the **pulse-frontend** repo (GitHub: [ciphera-net/pulse](https://github.com/ciphera-net/pulse)). The backend (pulse-backend) can be tagged separately if you version it; the single product changelog lives here.
## Who updates the changelog
The person cutting the release (or the PR author merging the release PR) is responsible for updating `CHANGELOG.md` before the tag is created. No release tag should be pushed without a corresponding changelog entry.
## When to update
- **Before** creating the git tag for the release.
- Move items from the `[Unreleased]` section into a new version section (e.g. `[0.2.0] - YYYY-MM-DD`), then clear or repopulate `[Unreleased]` as needed.
- Update the comparison links at the bottom of `CHANGELOG.md` (e.g. add `[0.2.0]: ...` and set `[Unreleased]` to `compare/v0.2.0...HEAD`).
## Version numbering (0.x.y)
While Pulse is in initial development we use **0.x.y**:
- **0** = initial development; we may change behaviour or “API” without a new major version.
- **x** (minor) = new features or small breaking changes; bump for a release that adds functionality.
- **y** (patch) = bug fixes only; bump for a release that only fixes bugs.
When we are ready to commit to stability we release **1.0.0** and then follow strict [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## How to tag a release
1. Ensure `CHANGELOG.md` has an entry for the new version (see **When to update** above).
2. (Optional) Run the changelog check so the version in the tag matches an entry in the changelog:
```bash
./scripts/check-changelog.sh 0.2.0
```
3. Commit any changelog (and link) updates, merge to the target branch (usually `main` for production).
4. Create an annotated tag (use the same version as in the changelog, with a `v` prefix):
```bash
git tag -a v0.2.0 -m "Release 0.2.0"
git push origin v0.2.0
```
Use the same version number in the tag as in the changelog (e.g. `v0.2.0` ↔ `[0.2.0]`).
## Deploy (staging and production)
- **Staging:** Push to the `staging` branch; Coolify deploys from `staging` to the staging environment.
- **Production:** Only the `main` branch is deployed to production. Merge `staging` → `main` when ready, then push. Tagging (e.g. `v0.2.0`) is done from `main` after the release commit is merged; Coolify auto-deploys on push to `main`.
So the usual flow is: merge release work (including changelog) to `main`, then create and push the tag from `main`.
## Checklist for each release
- [ ] Changelog updated: new version section with date, and `[Unreleased]` updated.
- [ ] Bottom-of-file comparison links updated in `CHANGELOG.md`.
- [ ] (Optional) `./scripts/check-changelog.sh <version>` passes.
- [ ] Changes merged to `main`.
- [ ] Tag created and pushed: `git tag -a vX.Y.Z -m "Release X.Y.Z"` then `git push origin vX.Y.Z`.

1177
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,7 @@
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"react-simple-maps": "^3.0.0",
"recharts": "^2.15.0",
"sonner": "^2.0.7",

31
scripts/check-changelog.sh Executable file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env bash
# * Verifies that CHANGELOG.md has an entry for the given version (e.g. 0.1.0 or v0.1.0).
# * Use before tagging a release; can be wired into CI.
# * Usage: ./scripts/check-changelog.sh <version>
set -e
VERSION="${1:-}"
CHANGELOG="${CHANGELOG:-CHANGELOG.md}"
if [ -z "$VERSION" ]; then
echo "Usage: $0 <version> (e.g. 0.1.0 or v0.1.0)" >&2
exit 1
fi
# Strip leading 'v' if present for consistent matching
NORMALIZED="${VERSION#v}"
if [ ! -f "$CHANGELOG" ]; then
echo "Error: $CHANGELOG not found (run from repo root)" >&2
exit 1
fi
# Keep a Changelog style: ## [1.0.0] or ## [1.0.0] - 2026-02-09
if grep -qE "^## \[${NORMALIZED}\]" "$CHANGELOG"; then
echo "OK: CHANGELOG has an entry for version $NORMALIZED"
exit 0
fi
echo "Error: CHANGELOG.md has no entry for version $NORMALIZED (expected a line like '## [$NORMALIZED] - YYYY-MM-DD')" >&2
exit 1