84 Commits

Author SHA1 Message Date
7c32d347b4 BLOG-97 Remove obsolete migration script for post and label tables (#131)
All checks were successful
Frontend CI / build (push) Successful in 1m21s
### Description

> [!WARNING]
> Removing `v0.1.0` version of migration from `_sqlx_migrations` table before deploying is require.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #97

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #131
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-12 22:40:12 +08:00
eb2c829659 NO-ISSUE Merged from release/0.3 (#130)
All checks were successful
Frontend CI / build (push) Successful in 1m24s
Reviewed-on: #130
2025-08-12 22:15:25 +08:00
f62fb15375 NO-ISSUE build: update backend version
All checks were successful
Frontend CI / build (push) Successful in 1m26s
Deployment / deployment (release) Successful in 5m19s
Auto Comment On PR / add_improve_comment (pull_request) Successful in 12s
PR Title Check / pr-title-check (pull_request) Successful in 13s
v0.3.1
2025-08-12 21:59:28 +08:00
fcada15211 BLOG-128 Fix logic for determining published post access based on user login status (#129)
Some checks failed
Frontend CI / build (push) Has been cancelled
### Description

The relationship between `is_published_only` and `has_logged_in`:

| is_published_only | has_logged_in | result |
| ----------------- | ------------- | ------ |
| T                 | T             | T      |
| T                 | F             | T      |
| F                 | T             | F      |
| F                 | F             | T      |

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #128

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #129
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-12 21:58:25 +08:00
a3892f2289 NO-ISSUE build: update app version
All checks were successful
Frontend CI / build (push) Successful in 1m11s
Deployment / deployment (release) Successful in 13m55s
v0.3.0
2025-08-06 23:01:34 +08:00
e6b41a768f BLOG-119 Restricted access to unpublished posts (#124)
All checks were successful
Frontend CI / build (push) Successful in 1m13s
Deployment / deployment (release) Successful in 6m59s
### Description

This PR introduces an authorization layer for the post feature. It ensures that create, update, and read operations for posts are properly controlled based on user authentication status and post visibility (published vs. unpublished).

#### Key Changes:

* **Restricted Access to Unpublished Posts**:
    * Unauthenticated users can no longer access unpublished posts via the `GET /post/{id}` endpoint. Attempting to do so will now result in an `HTTP 401 Unauthorized` error.
    * The `get_all_post_info` endpoint is now aware of the user's authentication status to correctly filter posts.

* **Authentication Required for Modifications**:
    * Creating (`POST /post`) and updating (`PUT /post/{id}`) posts now requires an authenticated user. The `user_id` is passed from the web handler through the controller to the use cases.

* **New Error Type**:
    * A new `PostError::Unauthorized` variant has been added to handle access control failures gracefully.

* **API & Core Logic Updates**:
    * The `PostController`, use cases (`GetFullPostUseCase`, `GetAllPostInfoUseCase`, etc.), and web handlers have been updated to accept and process the `user_id`.
    * The `GetFullPostUseCase` now contains the primary logic to prevent unauthenticated access to draft posts.
    * OpenAPI (Utopia) documentation has been updated to reflect these new authorization rules.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #119

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #124
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-06 22:13:54 +08:00
a9df43943e BLOG-90 Fix backend docker build error (#123)
All checks were successful
Frontend CI / build (push) Successful in 1m11s
### Description

- Using `alpine` for build environment.

<https://g.co/gemini/share/ad84493a13dd>

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #122.

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #123
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-06 21:44:06 +08:00
08c5262df6 BLOG-118 Fix to allow nullable published_time to support unpublished posts (#121)
All checks were successful
Frontend CI / build (push) Successful in 1m19s
### Description

This PR updates the application to handle posts that may not have a publication date (e.g., drafts) by making the `published_time` field optional across the entire post feature stack.

This ensures that draft posts can be processed and rendered without causing errors, and prevents search engine metadata from being generated for content that is not yet published.

#### Key Changes:

* **DTO & Schema (`postInfoResponseDto.ts`):**
    * The Zod schema for `PostInfoResponseSchema` has been updated to mark `published_time` as `.nullable()`.
    * The `PostInfoResponseDto` class now correctly handles a `null` value from the API, mapping it to `Date | null`.

* **Domain Entity (`postInfo.ts`):**
    * The core `PostInfo` entity's `publishedTime` property is now typed as `Date | null` to reflect the business logic that a post may be unpublished.

* **View Model (`postInfoViewModel.ts`):**
    * Updated `publishedTime` to be `Date | null`.
    * Added a new `isPublished` boolean getter for convenient conditional logic in the UI.
    * The `formattedPublishedTime` getter now returns `string | null`.
    * Dehydration and rehydration logic (`dehydrate`/`rehydrate`) has been updated to correctly handle the nullable `publishedTime`.

* **UI Component (`PostContentPage.svelte`):**
    * The component now uses the new `isPublished` flag to conditionally render the `<StructuredData>` component for SEO. This ensures that structured data is only included for posts that have been officially published.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #118

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #121
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-06 21:36:54 +08:00
71bae3d8ca BLOG-90 Intergrate error tracking with Sentry (#120)
All checks were successful
Frontend CI / build (push) Successful in 1m29s
### Description

There are several environment variables should be set:

- Frontend
  - `PUBLIC_SENTRY_DSN`
  - `SENTRY_AUTH_TOKEN`
- Backend
  - `SENTRY_DSN`

If the dsn isn't set, errors won't be sent to Sentry.

### Package Changes

_No response_

### Screenshots

![image.png](/attachments/22e49f8d-ac01-4d09-8ff0-7ce87b787055)

### Reference

Resolves #90

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #120
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-06 20:20:47 +08:00
171410e115 BLOG-48 SEO Improvement (#116)
All checks were successful
Frontend CI / build (push) Successful in 1m14s
### Description

#### Overview
This PR improves the website's SEO by:
1. Moving title and meta description tags from app.html to individual page components
2. Adding dynamic meta descriptions based on page content
3. Implementing structured data for blog posts using JSON-LD
4. Optimizing meta descriptions for better search engine visibility

#### Changes
- **app.html**: Removed static title and meta description tags
- **HomePage.svelte**: Added descriptive title parameter to generateTitle function
- **Terminal.svelte**: Dynamically generates meta description from terminal lines
- **PostContentPage.svelte**: Added meta description and structured data for blog posts
- **PostOverallPage.svelte**: Added descriptive meta description for blog listing page
- **StructuredData.svelte**: Created new component to generate JSON-LD structured data for blog posts

#### Benefits
- Improved SEO through better metadata management
- Enhanced search engine visibility with structured data
- More accurate and dynamic meta descriptions
- Better control over page-specific metadata

> [!NOTE]
> Since sitemap auto generating is a little more complex, it will be solved in #117 in the future.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #48

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #116
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-05 11:25:39 +08:00
c66bc86771 NO-ISSUE Merged from release/0.2 (#114)
All checks were successful
Frontend CI / build (push) Successful in 1m6s
Reviewed-on: #114
2025-08-04 07:35:45 +08:00
bc20385ff2 Merge branch 'release/0.2' into NO-ISSUE_merge_v0.2.2
All checks were successful
Frontend CI / build (push) Successful in 1m8s
Auto Comment On PR / add_improve_comment (pull_request) Successful in 17s
PR Title Check / pr-title-check (pull_request) Successful in 16s
2025-08-04 07:32:40 +08:00
a6e1ee3c1c BLOG-112 Add Google Analytics integration and update environment variables (#113)
All checks were successful
Frontend CI / build (push) Successful in 1m11s
### Description

- New env var: PUBLIC_GA_MEASUREMENT_ID=G-XXX

### Package Changes

_No response_

### Screenshots

![image.png](/attachments/5d830c44-f447-4e06-907a-2a0cbf976ca8)

### Reference

Resolves #112

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #113
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-04 07:29:10 +08:00
18f29655bf BLOG-92 Fix improve google font loading efficiency (#111)
All checks were successful
Frontend CI / build (push) Successful in 1m10s
### Description

Reference: https://web.dev/learn/performance/understanding-the-critical-path?utm_source=lighthouse&utm_medium=lr&hl=zh-tw#render-blocking_resources/

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #92

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #111
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-02 15:26:49 +08:00
b953d0bf0d BLOG-109 Fix published_time schema to include offset (#110)
All checks were successful
Frontend CI / build (push) Successful in 1m8s
### Description

Reference: https://zod.dev/api?id=iso-dates#iso-datetimes

- Add `{ offset: true }` as options.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #109

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #110
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-02 14:55:44 +08:00
a5f66616c4 BLOG-104 Implement CRUD functionality for Posts (#108)
All checks were successful
Frontend CI / build (push) Successful in 1m8s
### Description

This pull request introduces the core functionality for creating and updating posts, completing the backend CRUD operations for the `post` feature. It includes new API endpoints, database schema changes, and corresponding updates across the entire application stack from the database layer to the frontend.

#### Backend API

-   **Added new authenticated endpoints:**
    -   `POST /post`: To create a new post.
    -   `PUT /post/{id}`: To update an existing post.
-   Implemented the full vertical slice for these operations, including:
    -   `CreatePostUseCase` and `UpdatePostUseCase`.
    -   Repository and DB service methods for creating, updating, and associating posts with labels.
    -   Transactional database operations to ensure data integrity when creating/updating posts and their associated labels.

#### Database

-   Added a new migration to include an `"order"` column in the `post_label` table.
-   This column preserves the user-defined order of labels for each post.
-   Queries have been updated to fetch and sort labels based on this new column.

#### API Schema & Documentation

-   Enhanced `utoipa` OpenAPI documentation with more specific formats for data types:
    -   `#[schema(format = Uri)]` for URLs like `preview_image_url`.
    -   `#[schema(format = Email)]` for user emails.
    -   `#[schema(format = DateTime)]` for timestamps.
-   Standardized the `published_time` field to use the RFC3339 string format instead of a numeric timestamp, improving API clarity and interoperability.

#### Frontend

-   Updated the `PostInfoResponseDto` in the frontend to correctly parse the new `DateTime` (ISO string) format for `published_time`.

#### Refactoring

-   Renamed `get_full_post` to a more descriptive `get_post_by_id` across the post feature module for better code clarity.

### Package Changes

```toml
utoipa = { version = "5.4.0", features = [
    "actix_extras",
    "non_strict_integers",
    "url",
] }
```

### Screenshots

_No response_

### Reference

Resolves #104

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #108
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-02 14:35:27 +08:00
71528294ae BLOG-105 Implement CRUD functionality for Labels (#107)
All checks were successful
Frontend CI / build (push) Successful in 1m8s
### Description

This PR introduces full CRUD (Create, Read, Update) functionality for post labels, implemented by following the existing Clean Architecture.

#### Backend

* **New API Endpoints for Label Management:**
    * `POST /label`: Create a new label (**authentication required**).
    * `PUT /label/{id}`: Update a label by its ID (**authentication required**).
    * `GET /label`: Get all labels.

* **Architectural Implementation:**
    * **Delivery Layer**: Added `CreateLabelRequestDto`, `UpdateLabelRequestDto`, and updated `PostController` with methods to handle label-related operations.
    * **Application Layer**: Created corresponding use cases (`CreateLabelUseCase`, `UpdateLabelUseCase`, `GetAllLabelsUseCase`) to handle business logic.
    * **Gateway/Framework Layer**: Implemented `LabelRepository` and `LabelDbService` to manage database interactions, including creating, updating, and querying labels.

* **Route Adjustment:**
    * The route for fetching all post info has been changed from `GET /post/all` to `GET /post` to be more RESTful.

#### Frontend

* **API Call Update:**
    * To match the backend route change, the API path for fetching all posts is updated from `/post/all` to `/post`.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #105

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #107
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-02 10:46:00 +08:00
e255e076dc BLOG-103 Add API documentation with Utoipa (#106)
All checks were successful
Frontend CI / build (push) Successful in 1m8s
### Description

This PR integrates the **`utoipa`** and **`utoipa-redoc`** crates to automatically generate OpenAPI-compliant API documentation for the backend project.

#### Overview

To improve development efficiency and API maintainability, this change introduces `utoipa` to automate the API documentation process. By adding specific attribute macros to the source code, we can generate detailed API specifications directly and serve them through an interactive UI provided by `utoipa-redoc`.

#### Key Changes

* **Dependencies Added**
    * Added `utoipa`, `utoipa-gen`, and `utoipa-redoc` to `Cargo.toml`.
    * `utoipa` is used to define OpenAPI objects.
    * `utoipa-redoc` is used to serve the ReDoc documentation UI.

* **Code Refactoring**
    * **HTTP handler logic** in each feature (`auth`, `image`, `post`) has been extracted from the `..._web_routes.rs` files into their own dedicated files (e.g., `get_post_by_id_handler.rs`). This makes the code structure cleaner and simplifies adding documentation attributes to each handler.
    * Renamed the `PostController` method from `get_full_post` to `get_post_by_id` for a more RESTful-compliant naming convention.

* **API Doc Annotation**
    * Added `#[derive(ToSchema)]` or `#[derive(IntoParams)]` to all DTOs (Data Transfer Objects) so they can be recognized by `utoipa` to generate the corresponding schemas.
    * Added the `#[utoipa::path]` macro to all HTTP handler functions, describing the API's path, HTTP method, tags, summary, expected responses, and security settings.

* **Doc Aggregation & Serving**
    * Added an `..._api_doc.rs` file in each feature module to aggregate all API paths within that module.
    * Added a new `api_doc.rs` file in the `server` crate to merge the OpenAPI documents from all features, set global information (like title, version, and the OAuth2 security scheme), and serve the documentation page on the `/redoc` route using `Redoc::with_url`.

### Package Changes

```toml
utoipa = { version = "5.4.0", features = ["actix_extras"] }
utoipa-redoc = { version = "6.0.0", features = ["actix-web"] }
```

### Screenshots

![image.png](/attachments/f5b4b268-f550-4d9e-9321-49a00f6b8e1a)

### Reference

Resolves #103

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #106
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-02 06:51:37 +08:00
f986810540 BLOG-100 User retrieval functionality in authentication module (#102)
All checks were successful
Frontend CI / build (push) Successful in 1m9s
### Description

- Endpoint: GET `/me`, returns the whole user data.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #100

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #102
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-01 18:42:22 +08:00
197d7773ef BLOG-86 Checking authentication before uploading image (#101)
All checks were successful
Frontend CI / build (push) Successful in 1m8s
### Description

This PR introduces a generic authentication middleware to protect application routes. The primary goal is to prevent unauthenticated users from uploading images.

#### Changes Implemented

* **Authentication Middleware**:
    * Created a new `auth_middleware` that checks the user's session for a valid `user_id`.
    * If a `user_id` exists, it's added to the request extensions, making it available to downstream handlers.

* **`UserId` Extractor**:
    * A `UserId` type that implements `FromRequest` has been added.
    * This allows route handlers to declaratively require authentication by simply adding `user_id: UserId` as a parameter. If the user is not logged in, the extractor automatically returns an `ErrorUnauthorized` response.

* **Route Protection**:
    * The `upload_image_handler` now includes the `UserId` extractor, securing the endpoint.
    * A new `/auth/me` route has been added for easily verifying the logged-in user's ID during development and testing.

* **Minor Refinements**:
    * The `logout_handler` now uses `session.clear()` for more robust session termination.
    * Corrected the default Redis URL from `redis://127.0.1:6379` to `redis://127.0.0.1:6379`.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #86

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #101
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-01 18:26:39 +08:00
0d6810f3d5 NO-ISSUE Remove .sqlx from gitignore (#99)
All checks were successful
Frontend CI / build (push) Successful in 1m9s
### Description

- `.sqlx` should be check into version control system because it is required when rust compiling if there is no available online sql server.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

__NO_ISSUE__

### Checklist

- [x] A milestone is set
- [ ] The related issuse has been linked to this branch

Reviewed-on: #99
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-01 15:17:41 +08:00
c6661f3222 BLOG-95 Seperate SQL migration files (#98)
All checks were successful
Frontend CI / build (push) Successful in 1m10s
### Description

- In beta environment, `v0.3.0` migration has been run, a manual revertion is required; in real environment, there is nothing to do, but to do #97 and remove migration record for `v0.1.1` manually.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #95

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #98
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-01 15:02:29 +08:00
9c88b4bb55 BLOG-94 Create user in DB when first login through OIDC (#96)
All checks were successful
Frontend CI / build (push) Successful in 1m8s
### Description

This PR introduces the functionality to persist user information in the database. When a user logs in via OIDC for the first time, a new user record is created. Subsequent logins will retrieve the existing user data from the database.

This change ensures that users have a persistent identity within our system, identified by their unique combination of OIDC issuer and subject ID.

#### Key Changes

* **User Persistence Logic**:
    * In `ExchangeAuthCodeUseCase`, after successfully exchanging the authorization code, the logic now checks if the user exists in our database using their `issuer` and `source_id`.
    * If the user is not found (`AuthError::UserNotFound`), a new record is created in the `user` table.
    * The `User` entity returned by the use case now contains the internal database `id`.

* **Database Integration in Auth Feature**:
    * Introduced a new `UserDbService` trait and its `sqlx`-based implementation, `UserDbServiceImpl`, to handle database operations for users.
    * The `AuthRepository` is extended to include methods for querying (`get_user_by_source_id`) and saving (`save_user`) users, delegating the calls to the new `UserDbService`.
    * The dependency injection container in `server/src/container.rs` has been updated to provide the `UserDbServiceImpl` to the `AuthRepositoryImpl`.

* **Domain and Data Model Updates**:
    * The `User` domain entity now includes `id` (the database primary key) and `issuer` (from OIDC claims) to uniquely identify a user across different identity providers.
    * The `UserResponseDto` now exposes the internal `id` instead of the `source_id`.

* **Session Management**:
    * The user's session now stores the database `user_id` (`i32`) instead of the entire user object. This is more efficient and secure.
    * Session keys have been centralized into a `constants.rs` file for better maintainability.

#### Database Changes

* A new database migration has been added to create the `user` table.
* The table includes columns for `id`, `issuer`, `source_id`, `displayed_name`, and `email`.
* A **`UNIQUE` index** has been created on `(source_id, issuer)` to guarantee that each user from a specific identity provider is stored only once.

#### Refactoring

* Minor refactoring in the `image` feature to change `id: Option<i32>` to `id: i32` for consistency with the new `User` entity model.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #94

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #96
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-08-01 13:24:08 +08:00
dd0567c937 BLOG-85 Implement OIDC authentication (#93)
All checks were successful
Frontend CI / build (push) Successful in 1m7s
### Description

- Login with configured OIDC issuer, and then save the logged in information in server session.
- Endpoints:
  - GET `/auth/login`
  - GET `/auth/callback`
  - GET `/auth/logout`

### Package Changes

```toml
actix-session = { version = "0.10.1", features = ["redis-session"] }
hex = "0.4.3"
openidconnect = { version = "4.0.1", features = [
    "reqwest",
    "reqwest-blocking",
] }
```

### Screenshots

<video src="attachments/8b15b576-61db-41b9-8587-b4b885018c93" title="Screencast From 2025-07-30 03-34-26.mp4" controls></video>

### Reference

Resolves #85

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #93
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-30 03:46:49 +08:00
8d7b59263d NO-ISSUE build: update frontend version
All checks were successful
Frontend CI / build (push) Successful in 1m6s
Deployment / deployment (release) Successful in 7m9s
PR Title Check / pr-title-check (pull_request) Successful in 16s
v0.2.2
2025-07-28 00:22:39 +08:00
64ebfaa3e9 BLOG-87 Fix to unify post content title color (#88)
All checks were successful
Frontend CI / build (push) Successful in 1m5s
### Description

- Enhance typography and color consistency in PostPreview and PostContentPage
- Add tailwind configuration for custom typography styles

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #87

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #88
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-28 00:21:09 +08:00
ab3050db69 BLOG-78 Backend image upload and download (#84)
All checks were successful
Frontend CI / build (push) Successful in 1m4s
### Description

- Add some endpoints about image:
  - POST `/image/upload`
  - GET `/image/{id}`

> [!NOTE]
> Since there isn't identity authentication, the `/image` endpoints should be restricted to private network in nginx.

> [!NOTE]
> Volume for backend should be configured in `pod.yaml`.

### Package Changes

```toml
actix-multipart = "0.7.2"
```

### Screenshots

_No response_

### Reference

Resolves #78

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #84
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-27 13:10:46 +08:00
f400bcf486 BLOG-79 AI review bot (#83)
All checks were successful
Frontend CI / build (push) Successful in 1m5s
### Description

- Use Qudo Merge as self-hosted PR agent
- Add a workflow that auto comment /improve command to start the agent

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #79

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #83
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-26 07:01:50 +08:00
95fabee99d BLOG-73 Change website title dynamically (#77)
All checks were successful
Frontend CI / build (push) Successful in 1m7s
### Description

- Use `generateTitle` to combine app name and page title.

### Package Changes

_No response_

### Screenshots

|Home|Post Overall|Post Content|
|-|-|-|
|![Screenshot From 2025-07-26 01-58-04.png](/attachments/70ed7440-bd5a-4e9d-a747-bb785c9f7e16)|![Screenshot From 2025-07-26 01-58-27.png](/attachments/58386f0d-e476-4795-8ac4-f0abc6586721)|![Screenshot From 2025-07-26 01-58-31.png](/attachments/cf7cb5a6-af5e-4dc6-907f-8cb8253f1b13)|

### Reference

Resolves #73

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #77
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-26 02:01:24 +08:00
9ad3809f47 BLOG-70 Add tooltip for post preview (#76)
All checks were successful
Frontend CI / build (push) Successful in 1m7s
### Description

- A a `title` attribute on the `<a>` element.
- Make the title as `<h2>` and the description as `<p>`.

### Package Changes

_No response_

### Screenshots

![image.png](/attachments/0d4b815e-d1c5-432c-8174-53273189a9c3)

### Reference

Resolves #

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #76
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-26 01:29:18 +08:00
ff2b86358d NO-ISSUE Merged from release/0.2 (#75)
All checks were successful
Frontend CI / build (push) Successful in 1m6s
Reviewed-on: #75
2025-07-26 01:03:43 +08:00
0896afe819 Merge branch 'main' into release/0.2
All checks were successful
PR Title Check / pr-title-check (pull_request) Successful in 17s
Frontend CI / build (push) Successful in 1m8s
2025-07-26 01:02:12 +08:00
462b1a6efb NO-ISSUE build: update frontend version
All checks were successful
PR Title Check / pr-title-check (pull_request) Successful in 17s
Frontend CI / build (push) Successful in 1m7s
Deployment / deployment (release) Successful in 5m38s
v0.2.1
2025-07-26 00:34:48 +08:00
7770a5b569 BLOG-72 Fix img cannot be shown on content page (#74)
All checks were successful
Frontend CI / build (push) Successful in 1m7s
### Description

<https://www.npmjs.com/package/sanitize-html>

![image.png](/attachments/f35293b6-7c80-4a6f-917e-fa0d4cffa804)

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #72

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #74
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-26 00:33:17 +08:00
d9b531f08d NO-ISSUE Merged from release/0.2 (#69)
All checks were successful
Frontend CI / build (push) Successful in 1m10s
Reviewed-on: #69
2025-07-25 10:33:47 +08:00
2039edf5e9 NO-ISSUE build: update app version
All checks were successful
Frontend CI / build (push) Successful in 1m7s
Deployment / deployment (release) Successful in 7m24s
PR Title Check / pr-title-check (pull_request) Successful in 16s
v0.2.0
2025-07-24 23:40:40 +08:00
96c661b6d5 NO-ISSUE Update document link to readme (#68)
All checks were successful
Frontend CI / build (push) Successful in 1m7s
### Description

As the title.

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

_NO-ISSUE_

### Checklist

- [x] A milestone is set
- [ ] The related issuse has been linked to this branch

Reviewed-on: #68
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-24 23:36:30 +08:00
3cb69f6e7c BLOG-45 Post content page (#67)
All checks were successful
Frontend CI / build (push) Successful in 1m8s
### Description

- Implement the content page
  - Parse markdown formant content to html by `markdown-it`
  - Use `sanitize-html` to prevent from XSS attack
  - Style the html with `tailwindcss-typography`
- Fix the issue when backend parse the password to url
- Fix and make the post info list from backend always sorted by id

### Package Changes

### Rust

```toml
percent-encoding = "2.3.1"
```

### Node

```json
{
  "@types/markdown-it": "^14.1.2",
  "@types/sanitize-html": "^2.16.0",
  "markdown-it": "^14.1.0",
  "sanitize-html": "^2.17.0"
}
```

### Screenshots

|Desktop|Mobile|
|-|-|
|![image.png](/attachments/0ec5718a-f804-432f-8e4b-e9dc22c080d2)|![beta.squidspirit.com_post(iPhone 12 Pro) (1).png](/attachments/b30d1b96-d4a4-4b2b-b9bd-90fd2592ab52)|

### Reference

Resolves #45

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #67
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-24 22:20:58 +08:00
4a924c1b92 BLOG-65 Establish beta environment (#66)
All checks were successful
Frontend CI / build (push) Successful in 1m4s
### Description

- Change some environment variables implementation
- Nginx configuration:

  ```nginx
  server {
      server_name beta.squidspirit.com;

      proxy_pass_request_headers on;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;

      location / {
          proxy_pass http://127.0.0.1:10013/;
      }

      location /api/ {
          proxy_pass http://127.0.0.1:10014/;
      }

      listen 443 ssl; # managed by Certbot
      ssl_certificate /etc/letsencrypt/live/beta.squidspirit.com/fullchain.pem; # managed by Certbot
      ssl_certificate_key /etc/letsencrypt/live/beta.squidspirit.com/privkey.pem; # managed by Certbot
      include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
      ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
  }

  server {
      if ($host = beta.squidspirit.com) {
          return 301 https://$host$request_uri;
      } # managed by Certbot

      server_name beta.squidspirit.com;
      listen 80;
      return 404; # managed by Certbot
  }
  ```

- Podman kube configuration:

  ```yaml
    apiVersion: v1
  kind: Secret
  metadata:
    name: beta-blog-secret
  data:
    DATABASE_PASSWORD: {{BASE64_PASSWORD}}

  ---

  apiVersion: v1
  kind: Pod
  metadata:
    name: beta-blog
  spec:
    containers:
      - name: postgres
        image: docker.io/library/postgres:17-alpine
        imagePullPolicy: always
        env:
          - name: POSTGRES_PASSWORD
            valueFrom:
              secretKeyRef:
                name: beta-blog-secret
                key: DATABASE_PASSWORD
        volumeMounts:
          - name: beta-blog-postgres
            mountPath: /var/lib/postgresql/data
      - name: backend
        image: registry.squidspirit.com/squid/beta-blog-backend:latest
        imagePullPolicy: always
        env:
          - name: DATABASE_PASSWORD
            valueFrom:
              secretKeyRef:
                name: beta-blog-secret
                key: DATABASE_PASSWORD
        volumeMounts:
          - name: beta-blog-localtime
            mountPath: /etc/localtime
            readonly: true
        ports:
          - hostPort: 10014
            hostIP: 127.0.0.1
            containerPort: 8080
      - name: frontend
        image: registry.squidspirit.com/squid/beta-blog-frontend:latest
        imagePullPolicy: always
        env:
          - name: PUBLIC_API_BASE_URL
            value: https://beta.squidspirit.com/api/
        volumeMounts:
          - name: beta-blog-localtime
            mountPath: /etc/localtime
            readonly: true
        ports:
          - hostPort: 10013
            hostIP: 127.0.0.1
            containerPort: 3000
    volumes:
      - name: beta-blog-localtime
        hostPath:
          path: /etc/localtime
      - name: beta-blog-postgres
        persistentVolumeClaim:
          claimName: beta-blog-postgres
  ```

### Package Changes

_No response_

### Screenshots

_No response_

### Reference

Resolves #65

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #66
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-24 02:23:44 +08:00
c2462fe537 BLOG-44 Post overall page (#64)
All checks were successful
Frontend CI / build (push) Successful in 1m6s
### Description

- Change the format of color response

  ```json
  {
    "red": 0,
    "green": 255,
    "blue": 128,
    "alpha": 255
  }
  ```

- The relationship between the label's background color and its highlight color is calculated. The method involves first converting the RGB color value to HSL, then decreasing the L (lightness) component, and finally converting it back to RGB.

### Package Changes

```json
{
  "zod": "^4.0.5"
}
```

### Screenshots

|Desktop|Mobile|
|-|-|
|![image.png](/attachments/851450c4-0975-4b66-9bf7-606d0114c03e)|![image.png](/attachments/f263d65c-89e9-4439-8d50-ae92ae9482ac)|

### Reference

Resolves #44

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #64
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-24 00:32:20 +08:00
f66f4ecc79 BLOG-62 Custom not found page (#63)
All checks were successful
Frontend CI / build (push) Successful in 1m0s
### Description

As the title.

### Package Changes

_No response_

### Screenshots

![image.png](/attachments/536ca4c6-1043-46bb-b1f0-1614f8501f9f)

### Reference

Resolves #62

### Checklist

- [x] A milestone is set
- [x] The related issuse has been linked to this branch

Reviewed-on: #63
Co-authored-by: SquidSpirit <squid@squidspirit.com>
Co-committed-by: SquidSpirit <squid@squidspirit.com>
2025-07-23 05:49:46 +08:00
3f02eaa568 BLOG-58 Rewrite frontend with svelte kit (#61)
All checks were successful
Frontend CI / build (push) Successful in 1m1s
Reviewed-on: #61
2025-07-23 05:34:25 +08:00
06c66e1a18 BLOG-58 fix: eslint error
All checks were successful
Frontend CI / build (push) Successful in 1m3s
PR Title Check / pr-title-check (pull_request) Successful in 16s
2025-07-23 05:32:35 +08:00
f195b9c108 BLOG-58 refactor: run format
Some checks failed
Frontend CI / build (push) Failing after 1m3s
PR Title Check / pr-title-check (pull_request) Successful in 13s
2025-07-23 05:27:46 +08:00
cefdc94e03 BLOG-58 fix: workflow node version
Some checks failed
PR Title Check / pr-title-check (pull_request) Successful in 17s
Frontend CI / build (push) Failing after 53s
2025-07-23 05:23:29 +08:00
eb4b2f4d6a BLOG-58 refactor: remove nextjs code
Some checks failed
PR Title Check / pr-title-check (pull_request) Successful in 13s
Frontend CI / build (push) Failing after 44s
2025-07-23 05:19:36 +08:00
b0215d167d BLOG-58 feat: add Dockerfile and configure SvelteKit with Node adapter
Some checks failed
Frontend CI / build (push) Has been cancelled
2025-07-23 05:18:08 +08:00
93389813f8 BLOG-58 docs: update frontend framework from Next.js to SvelteKit in README
All checks were successful
Frontend CI / build (push) Successful in 1m33s
2025-07-23 04:55:27 +08:00
7126818745 BLOG-58 fix: time display logic in TerminalLastLine component
All checks were successful
Frontend CI / build (push) Successful in 1m33s
2025-07-23 04:53:20 +08:00
ecb8384c22 BLOG-58 feat: add app versioning support and update layout to include version meta tag
All checks were successful
Frontend CI / build (push) Successful in 1m32s
2025-07-23 04:49:08 +08:00