diff --git a/CHANGELOG.md b/CHANGELOG.md
index bdb7ea502..cfc95d387 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- Added a blog post: _Hacktoberfest 2025_
+
### Changed
- Removed the deprecated `ITEM` activity type
diff --git a/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts b/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts
index fb581c72e..b42ae3594 100644
--- a/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts
+++ b/apps/api/src/app/endpoints/sitemap/sitemap.controller.ts
@@ -37,6 +37,7 @@ export class SitemapController {
response.setHeader('content-type', 'application/xml');
response.send(
interpolate(this.sitemapXml, {
+ blogPosts: this.sitemapService.getBlogPosts({ currentDate }),
personalFinanceTools: this.configurationService.get(
'ENABLE_FEATURE_SUBSCRIPTION'
)
diff --git a/apps/api/src/app/endpoints/sitemap/sitemap.service.ts b/apps/api/src/app/endpoints/sitemap/sitemap.service.ts
index 3774d2274..b8cdfc5c6 100644
--- a/apps/api/src/app/endpoints/sitemap/sitemap.service.ts
+++ b/apps/api/src/app/endpoints/sitemap/sitemap.service.ts
@@ -17,6 +17,121 @@ export class SitemapService {
private readonly i18nService: I18nService
) {}
+ public getBlogPosts({ currentDate }: { currentDate: string }) {
+ const rootUrl = this.configurationService.get('ROOT_URL');
+
+ return [
+ {
+ languageCode: 'de',
+ routerLink: ['2021', '07', 'hallo-ghostfolio']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2021', '07', 'hello-ghostfolio']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2022', '01', 'ghostfolio-first-months-in-open-source']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2022', '07', 'ghostfolio-meets-internet-identity']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2022', '07', 'how-do-i-get-my-finances-in-order']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2022', '08', '500-stars-on-github']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2022', '10', 'hacktoberfest-2022']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2022', '11', 'black-friday-2022']
+ },
+ {
+ languageCode: 'en',
+ routerLink: [
+ '2022',
+ '12',
+ 'the-importance-of-tracking-your-personal-finances'
+ ]
+ },
+ {
+ languageCode: 'de',
+ routerLink: ['2023', '01', 'ghostfolio-auf-sackgeld-vorgestellt']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '02', 'ghostfolio-meets-umbrel']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '03', 'ghostfolio-reaches-1000-stars-on-github']
+ },
+ {
+ languageCode: 'en',
+ routerLink: [
+ '2023',
+ '05',
+ 'unlock-your-financial-potential-with-ghostfolio'
+ ]
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '07', 'exploring-the-path-to-fire']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '08', 'ghostfolio-joins-oss-friends']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '09', 'ghostfolio-2']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '09', 'hacktoberfest-2023']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '11', 'black-week-2023']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2023', '11', 'hacktoberfest-2023-debriefing']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2024', '09', 'hacktoberfest-2024']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2024', '11', 'black-weeks-2024']
+ },
+ {
+ languageCode: 'en',
+ routerLink: ['2025', '09', 'hacktoberfest-2025']
+ }
+ ]
+ .map(({ languageCode, routerLink }) => {
+ return this.createRouteSitemapUrl({
+ currentDate,
+ languageCode,
+ rootUrl,
+ route: {
+ routerLink: ['blog', ...routerLink],
+ path: undefined
+ }
+ });
+ })
+ .join('\n');
+ }
+
public getPersonalFinanceTools({ currentDate }: { currentDate: string }) {
const rootUrl = this.configurationService.get('ROOT_URL');
@@ -43,20 +158,21 @@ export class SitemapService {
});
return personalFinanceTools.map(({ alias, key }) => {
- const location = [
- rootUrl,
- languageCode,
+ const routerLink = [
resourcesPath,
personalFinanceToolsPath,
`${productPath}-${alias ?? key}`
- ].join('/');
-
- return [
- ' ',
- ` ${location} `,
- ` ${currentDate}T00:00:00+00:00 `,
- ' '
- ].join('\n');
+ ];
+
+ return this.createRouteSitemapUrl({
+ currentDate,
+ languageCode,
+ rootUrl,
+ route: {
+ routerLink,
+ path: undefined
+ }
+ });
});
}).join('\n');
}
diff --git a/apps/api/src/assets/sitemap.xml b/apps/api/src/assets/sitemap.xml
index fb2a5403e..2d4d121bf 100644
--- a/apps/api/src/assets/sitemap.xml
+++ b/apps/api/src/assets/sitemap.xml
@@ -5,5 +5,6 @@
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
${publicRoutes}
+ ${blogPosts}
${personalFinanceTools}
diff --git a/apps/api/src/middlewares/html-template.middleware.ts b/apps/api/src/middlewares/html-template.middleware.ts
index 665b93354..892b1ab5e 100644
--- a/apps/api/src/middlewares/html-template.middleware.ts
+++ b/apps/api/src/middlewares/html-template.middleware.ts
@@ -75,6 +75,10 @@ const locales = {
'/en/blog/2024/11/black-weeks-2024': {
featureGraphicPath: 'assets/images/blog/black-weeks-2024.jpg',
title: `Black Weeks 2024 - ${title}`
+ },
+ '/en/blog/2025/09/hacktoberfest-2025': {
+ featureGraphicPath: 'assets/images/blog/hacktoberfest-2025.png',
+ title: `Hacktoberfest 2025 - ${title}`
}
};
diff --git a/apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.component.ts b/apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.component.ts
new file mode 100644
index 000000000..72990ca47
--- /dev/null
+++ b/apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.component.ts
@@ -0,0 +1,17 @@
+import { publicRoutes } from '@ghostfolio/common/routes/routes';
+
+import { Component } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+import { RouterModule } from '@angular/router';
+
+@Component({
+ host: { class: 'page' },
+ imports: [MatButtonModule, RouterModule],
+ selector: 'gf-hacktoberfest-2025-page',
+ templateUrl: './hacktoberfest-2025-page.html'
+})
+export class Hacktoberfest2025PageComponent {
+ public routerLinkAbout = publicRoutes.about.routerLink;
+ public routerLinkBlog = publicRoutes.blog.routerLink;
+ public routerLinkOpenStartup = publicRoutes.openStartup.routerLink;
+}
diff --git a/apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.html b/apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.html
new file mode 100644
index 000000000..318d86aa0
--- /dev/null
+++ b/apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.html
@@ -0,0 +1,202 @@
+
+
+
+
+
+
Hacktoberfest 2025
+
2025-09-27
+
+
+
+
+ Ghostfolio is joining
+ Hacktoberfest for the fourth
+ time and we are looking
+ forward to meeting new open-source contributors along the way. Every
+ year in October, Hacktoberfest celebrates open source by
+ highlighting projects, maintainers, and contributors worldwide. Open
+ source maintainers around the globe dedicate extra time to support
+ new contributors while guiding them through their first pull
+ requests on
+ GitHub .
+
+
+
+
+ Meet Ghostfolio: a modern Dashboard for Personal Finance
+
+
+ Ghostfolio is a web application
+ that makes it easy to manage your personal finances. It aggregates
+ your assets and helps you make informed decisions to balance your
+ portfolio or plan future investments.
+
+
+ The software is fully written in
+ TypeScript and
+ organized as an Nx workspace, utilizing
+ the latest framework releases. The backend is based on
+ NestJS in combination with
+ PostgreSQL as a database
+ together with Prisma and
+ Redis for caching. The frontend is
+ developed with Angular .
+
+
+ With over 200 contributors, the OSS project is used daily by a
+ growing global community. Ghostfolio counts more than
+ 6’600 stars on GitHub
+ and
+ 1’600’000+ pulls on Docker Hub , standing out for its simple and user-friendly experience.
+
+
+
+ How you can make an impact
+
+ Every contribution makes a difference. Whether it is implementing
+ new features, resolving bugs, refactoring code, enhancing
+ documentation, adding unit tests, or translating content into
+ another language, you can actively shape our project.
+
+
+ New to our codebase? No worries! We have labeled a few
+ issues
+ with hacktoberfest
that are ideal for newcomers.
+
+
+ The official Hacktoberfest website provides some valuable
+ resources for beginners
+ to start contributing in open source.
+
+
+
+ Connect with us
+
+ If you have further questions or ideas, please join our
+ Slack
+ community or get in touch on X
+ @ghostfolio_ .
+
+
+ We look forward to collaborating.
+ Thomas from Ghostfolio
+
+
+
+
+
+ Angular
+
+
+ Community
+
+
+ Dashboard
+
+
+ Docker
+
+
+ Finance
+
+
+ Fintech
+
+
+ Ghostfolio
+
+
+ GitHub
+
+
+ Hacktoberfest
+
+
+ Hacktoberfest 2025
+
+
+ Investment
+
+
+ NestJS
+
+
+ Nx
+
+
+ October
+
+
+ Open Source
+
+
+ OSS
+
+
+ Personal Finance
+
+
+ Portfolio
+
+
+ Portfolio Tracker
+
+
+ Prisma
+
+
+ Redis
+
+
+ Software
+
+
+ TypeScript
+
+
+ UX
+
+
+ Wealth
+
+
+ Wealth Management
+
+
+ Web Application
+
+
+
+
+
+
+ Blog
+
+
+ Hacktoberfest 2025
+
+
+
+
+
+
+
diff --git a/apps/client/src/app/pages/blog/blog-page-routing.module.ts b/apps/client/src/app/pages/blog/blog-page-routing.module.ts
index 0e00ee530..9b352b7a8 100644
--- a/apps/client/src/app/pages/blog/blog-page-routing.module.ts
+++ b/apps/client/src/app/pages/blog/blog-page-routing.module.ts
@@ -201,6 +201,15 @@ const routes: Routes = [
(c) => c.BlackWeeks2024PageComponent
),
title: 'Black Weeks 2024'
+ },
+ {
+ canActivate: [AuthGuard],
+ path: '2025/09/hacktoberfest-2025',
+ loadComponent: () =>
+ import(
+ './2025/09/hacktoberfest-2025/hacktoberfest-2025-page.component'
+ ).then((c) => c.Hacktoberfest2025PageComponent),
+ title: 'Hacktoberfest 2025'
}
];
diff --git a/apps/client/src/app/pages/blog/blog-page.html b/apps/client/src/app/pages/blog/blog-page.html
index babeec4c6..88b685d33 100644
--- a/apps/client/src/app/pages/blog/blog-page.html
+++ b/apps/client/src/app/pages/blog/blog-page.html
@@ -8,6 +8,30 @@
finance
+
+
+
+
+
@if (hasPermissionForSubscription) {
diff --git a/apps/client/src/assets/images/blog/hacktoberfest-2025.png b/apps/client/src/assets/images/blog/hacktoberfest-2025.png
new file mode 100644
index 000000000..ab04e6dce
Binary files /dev/null and b/apps/client/src/assets/images/blog/hacktoberfest-2025.png differ