Skip to content

Commit 91d391f

Browse files
authored
Merge pull request #446 from Liturgical-Calendar/development
Release v5.7
2 parents 7335646 + c9427c3 commit 91d391f

File tree

117 files changed

+6826
-2913
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+6826
-2913
lines changed

.claude/commands/coderabbit.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Run coderabbit --plain, let it run as long as it needs (run it in the background).
2+
3+
Evaluate the fixes and considerations. Fix major issues, critical issues, and only fix the nits if they make sense even if they seem out of scope.
4+
5+
Once those changes are implemented, run CodeRabbit CLI one more time to make sure
6+
we addressed all the critical issues and didn't introduce any additional bugs.
7+
8+
Only run the loop up to four times. If on the fourth run you don't find any critical issues,
9+
ignore the nits and you're complete. Give me a summary of everything that was
10+
completed and why.

.claude/commands/merge.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Steps to Merge and Clean Up
2+
3+
1. Merge the PR using `gh pr merge <pr-number> --merge --delete-branch`, handling any conflicts if needed.
4+
2. Confirm the merge was successful by checking the PR status: `gh pr view <pr-number>`.
5+
3. Checkout the target branch (the branch the PR was merged into, e.g., `master` or `development`).
6+
4. Pull the changes: `git pull origin <target-branch>`.
7+
5. Delete the local branch if it wasn't already deleted: `git branch -d <branch-name>`.

.claude/commands/release.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Prepare a New Release
2+
3+
Prepare a new release for the Liturgical Calendar API.
4+
5+
## Step 1: Update API Version
6+
7+
Update the API version in two locations:
8+
9+
1. **CalendarHandler.php** (`src/Handlers/CalendarHandler.php`):
10+
- Find `public const API_VERSION = 'X.Y';`
11+
- Increment to the next minor version (e.g., `5.6``5.7`)
12+
- If there are breaking changes, increment the major version instead (e.g., `5.6``6.0`)
13+
14+
2. **openapi.json** (`jsondata/schemas/openapi.json`):
15+
- Find `"version": "X.Y"` in the `info` section
16+
- Update to match the new version
17+
18+
## Step 2: Update CHANGELOG.md
19+
20+
Add a new entry at the top of the changelog (after any commented unreleased section):
21+
22+
1. **Format**: `## [vX.Y](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/releases/tag/vX.Y) (Month DDth YYYY)`
23+
24+
2. **Changes**: List the changes made since the last release as bullet points. Check git log for commits since the last release tag.
25+
26+
3. **Liturgical celebration note**: Check if today has a significant liturgical celebration:
27+
- First, try fetching from local API: `http://localhost:8000/calendar?year_type=CIVIL`
28+
- If local is not running, use: `https://litcal.johnromanodorazio.com/api/dev/calendar?year_type=CIVIL`
29+
- Use `Accept-Language: en-US` header
30+
- Filter the `litcal` results for entries where `date` matches today's date formatted as RFC 3339 (e.g., `2025-12-15T00:00:00+00:00`)
31+
- If there's a celebration with grade >= FEAST (grade 5 or higher), or it's a notable memorial, add a note similar to previous entries:
32+
- "Saint X, pray for us! [emoji]"
33+
- "Happy Feast of X! [emoji]"
34+
- "X, [relevant prayer/exclamation]! [emoji]"
35+
- Look at previous changelog entries for style examples
36+
37+
## Step 3: Commit and Push
38+
39+
1. Stage the changed files:
40+
- `src/Handlers/CalendarHandler.php`
41+
- `jsondata/schemas/openapi.json`
42+
- `CHANGELOG.md`
43+
44+
2. Commit with message: `Release vX.Y`
45+
46+
3. Push to the `development` branch
47+
48+
## Step 4: Open Pull Request
49+
50+
Create a PR from `development` to `master`:
51+
52+
```bash
53+
gh pr create --base master --head development --title "Release vX.Y" --body "$(cat <<'EOF'
54+
## Release vX.Y
55+
56+
[Summary of changes from the changelog]
57+
58+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
59+
EOF
60+
)"
61+
```
62+
63+
Return the PR URL when complete.
64+
65+
---
66+
67+
**Note**: If unsure whether changes are breaking, ask the user before proceeding.

.env.example

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,91 @@
1-
### .env.example
2-
### Copy this file to .env.local (or .env.development or .env.production)
3-
### Set the values as needed.
4-
### Do not commit .env.local to version control, as it may contain sensitive information.
5-
### In production, API_BASE_PATH must be set, other variables are optional.
6-
### In development, the variables are used to launch the API and the Unit Test server,
7-
### and to help them connect to each other.
8-
9-
### Set the same value for WS_PORT in the Unit Test frontend project folder.
10-
### For more information, see https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/blob/development/public/LitCalTestServer.php
1+
# Copy this file to .env.local (or .env.development or .env.production)
2+
# Do not commit .env.local to version control, as it may contain sensitive information.
3+
# In production, API_BASE_PATH must be set; other variables are optional.
4+
# In development, the variables are used to launch the API and the Unit Test server.
5+
6+
# valid values: development, test, staging, production
7+
APP_ENV=development
8+
9+
##
10+
# WebSocket Configuration
11+
# Set the same value for WS_PORT in the Unit Test frontend project folder
12+
# See: https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/blob/development/public/LitCalTestServer.php
13+
##
1114
WS_PORT=8080
15+
# Maximum concurrent HTTP requests for WebSocket server (default: 10 in production, 4 in development)
16+
# Reduce this on memory-constrained servers to prevent overwhelming the API
17+
WS_MAX_CONCURRENCY=10
1218

13-
# Set the protocol to use for the API (default: "http")
19+
##
20+
# API Configuration
21+
# These variables control where the API launches and how the Unit Test server connects to it
22+
##
1423
API_PROTOCOL=http
15-
16-
# Set the hostname or IP address to use for the API (default: "localhost")
1724
API_HOST=localhost
18-
19-
# Set the port number to use for the API (default: "8000")
20-
# This will determine the port on which 'composer start' will launch the API.
21-
# It will also instruct the Unit Test server on the port on which it should look for the API.
22-
# If launching the API from VSCode tasks, make sure to set the same value in the tasks.json file.
25+
# This determines the port on which 'composer start' will launch the API
26+
# It also instructs the Unit Test server on which port to look for the API
27+
# If launching from VSCode tasks, set the same value in tasks.json
2328
API_PORT=8000
29+
# API Base Path - required in production or if dev server is not launched from public folder
30+
# The API cannot infer whether its path is `/api/` or `/api/{version}/`
31+
# In local development, leave empty (API runs at root)
32+
# In production, typically /api/dev or /api/v5
33+
API_BASE_PATH=
2434

25-
# Set the base path for the API (default: "/")
26-
# Required in production or if the development server is not launched from the public folder.
27-
# This value is needed for the Unit Test server to connect to the API,
28-
# and for the API to know the base path which it cannot infer otherwise.
29-
# It cannot know if the API path is `/`, `/api/` or `/api/{version}/`.
30-
# Please include a trailing slash for the API_BASE_PATH in any case.
31-
API_BASE_PATH=/
32-
33-
# Valid values: development | test | staging | production (optional)
34-
APP_ENV=development
35-
35+
##
3636
# JWT Authentication Configuration
37-
# IMPORTANT: Change JWT_SECRET to a strong random string in production (minimum 32 characters)
38-
# Generate a secure 64-character hex string with: php -r "echo bin2hex(random_bytes(32));"
37+
# Generate a secure 64-character hex string: php -r "echo bin2hex(random_bytes(32));"
38+
##
3939
JWT_ALGORITHM=HS256
4040
JWT_EXPIRY=3600
4141
JWT_REFRESH_EXPIRY=604800
42+
# IMPORTANT: Change to a strong random string in production (minimum 32 characters)
4243
JWT_SECRET=change-this-to-a-secure-random-string-in-production-minimum-32-chars
4344

44-
# Admin User Credentials (for initial JWT implementation)
45-
# IMPORTANT: Change these in production!
46-
# Generate password hash with: php -r "echo password_hash('your-password', PASSWORD_ARGON2ID);"
47-
# In development/test environments, if ADMIN_PASSWORD_HASH is missing or invalid,
48-
# authentication falls back to the default password "password".
49-
# In staging/production, a valid ADMIN_PASSWORD_HASH is required.
50-
ADMIN_PASSWORD_HASH=CHANGE_ME_GENERATE_WITH_password_hash
45+
##
46+
# Admin User Credentials
47+
# Generate password hash: php -r "echo password_hash('your-password', PASSWORD_ARGON2ID);"
48+
# In dev/test: falls back to default password "password" if hash is missing/invalid
49+
# In staging/production: a valid ADMIN_PASSWORD_HASH is required
50+
##
5151
ADMIN_USERNAME=admin
52+
ADMIN_PASSWORD_HASH=CHANGE_ME_GENERATE_WITH_password_hash
53+
54+
##
55+
# CORS Configuration
56+
# Comma-separated list of allowed origins for credentialed CORS requests (auth endpoints)
57+
# Use '*' to allow all origins (not recommended for production with cookie-based auth)
58+
# Example: https://example.com,https://admin.example.com
59+
##
60+
CORS_ALLOWED_ORIGINS=*
61+
62+
##
63+
# Rate Limiting for Authentication
64+
# Protects against brute-force attacks on the /auth/login endpoint
65+
##
66+
# Maximum failed login attempts before lockout (default: 5)
67+
RATE_LIMIT_LOGIN_ATTEMPTS=5
68+
# Time window in seconds for tracking attempts (default: 900 = 15 minutes)
69+
RATE_LIMIT_LOGIN_WINDOW=900
70+
# Path for rate limit data files (default: system temp directory)
71+
# RATE_LIMIT_STORAGE_PATH=/var/lib/litcal/rate_limits
72+
73+
##
74+
# HTTPS Enforcement
75+
# In staging/production, auth endpoints require HTTPS by default
76+
# Set to "false" to disable (e.g., if TLS is terminated at load balancer)
77+
# When using a reverse proxy, ensure it sets X-Forwarded-Proto header
78+
##
79+
HTTPS_ENFORCEMENT=true
80+
81+
##
82+
# Redis Configuration (for WebSocket server caching)
83+
# Uses Redis (or APCu fallback) for caching
84+
# Configure either Unix socket OR TCP connection (socket takes precedence)
85+
# If not configured, defaults to TCP 127.0.0.1:6379
86+
##
87+
# Unix socket connection (recommended for local Redis):
88+
# REDIS_SOCKET=/var/run/redis/redis.sock
89+
# TCP connection:
90+
# REDIS_HOST=127.0.0.1
91+
# REDIS_PORT=6379

.github/workflows/cldr_cron.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ jobs:
1111

1212
steps:
1313
- uses: actions/checkout@v4
14+
with:
15+
ref: development
1416

1517
- name: Get latest CLDR release tag
1618
id: cldr
@@ -51,6 +53,7 @@ jobs:
5153
remote_version=$(echo "$remote_version" | cut -d '.' -f 1)
5254
fi
5355
56+
echo "remote_version=$remote_version" >> $GITHUB_OUTPUT
5457
if [[ $remote_version == $local_version ]]; then
5558
echo "up_to_date=true" >> $GITHUB_OUTPUT
5659
else
@@ -84,4 +87,5 @@ jobs:
8487
Release notes: https://github.com/unicode-org/cldr-json/releases/tag/${{ steps.cldr.outputs.tag }}
8588
labels: dependencies, automated
8689
branch: update-cldr
90+
base: development
8791
delete-branch: true

.vscode/extensions.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"recommendations": [
3-
"shevaua.phpcs",
43
"bmewburn.vscode-intelephense-client",
54
"davidanson.vscode-markdownlint"
65
]

CHANGELOG.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
# CHANGELOG
22

33
<!--
4-
## [v5.7](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/releases/tag/v5.7) (unreleased)
4+
## [v5.8](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/releases/tag/v5.8) (unreleased)
55
66
* implement `filter` parameter for limited sets of calendar events, see issue [#43](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/issues/43)
77
-->
88

9+
## [v5.7](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/releases/tag/v5.7) (December 15th 2025)
10+
11+
* implement "Remember Me" functionality for login, see issue [#439](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/issues/439)
12+
* add production security features: login rate limiting, HTTPS enforcement, and APP_ENV validation, see issue [#428](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/issues/428)
13+
* add Redis cache with APCu fallback for improved performance, see issue [#420](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/issues/420)
14+
* implement cookie-only authentication (Phase 2.5) with HttpOnly cookies for enhanced security
15+
* add JWT authentication for /tests PUT/PATCH/DELETE endpoints, see issue [#443](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/issues/443)
16+
* improve CORS handling for authenticated requests with proper origin validation, see issue [#426](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/issues/426)
17+
* standardize dotenv configuration and add .env.test support
18+
19+
O Oriens, splendor lucis æternæ, veni! 🌅
20+
921
## [v5.6](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/releases/tag/v5.6) (November 28th 2025)
1022

1123
* fix bug [PUT/PATCH requests to /data serializing incorrectly](https://github.com/Liturgical-Calendar/LiturgicalCalendarAPI/issues/411)

CLAUDE.md

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ composer stop
4545
- `API_PROTOCOL` (http|https)
4646
- `API_HOST` (localhost in dev)
4747
- `API_PORT` (8000 in dev)
48-
- `API_BASE_PATH` (/ in dev)
48+
- `API_BASE_PATH` (empty in dev, e.g. /api/dev in production)
4949
- `APP_ENV` (development|test|staging|production) - **Required in non-localhost environments**
5050
- `development` / `test`: Allow default password if `ADMIN_PASSWORD_HASH` is unset (for testing convenience)
5151
- `staging` / `production`: Require `ADMIN_PASSWORD_HASH` to be configured (throws exception if missing)
@@ -62,16 +62,34 @@ composer stop
6262
- Required in `staging` and `production` environments
6363
- Optional in `development` and `test` environments (defaults to password "password")
6464

65-
**Protected Routes:** The following routes require JWT authentication (via `Authorization: Bearer <token>` header):
65+
**Protected Routes:** The following routes require JWT authentication (via HttpOnly cookie or `Authorization: Bearer <token>` header):
6666

6767
- `PUT /data/{category}/{calendar}` - Create calendar data
6868
- `PATCH /data/{category}/{calendar}` - Update calendar data
6969
- `DELETE /data/{category}/{calendar}` - Delete calendar data
7070

7171
**Authentication Endpoints:**
7272

73-
- `POST /auth/login` - Authenticate with username/password, returns access and refresh tokens
74-
- `POST /auth/refresh` - Refresh access token using refresh token
73+
- `POST /auth/login` - Authenticate with username/password, returns access and refresh tokens (sets HttpOnly cookies)
74+
- `POST /auth/refresh` - Refresh access token using refresh token (reads from cookie or body)
75+
- `POST /auth/logout` - End session and clear HttpOnly cookies
76+
- `GET /auth/me` - Check authentication state (returns user info from token, essential for cookie-based auth)
77+
78+
**Cookie-Based Authentication (Phase 2.5):**
79+
80+
The API supports full cookie-only authentication where:
81+
82+
- Tokens are stored in HttpOnly cookies (not accessible to JavaScript, mitigating token theft via XSS)
83+
- `JwtAuthMiddleware` reads token from cookie first, falls back to Authorization header
84+
- `RefreshHandler` reads refresh token from cookie, no request body needed
85+
- Frontend uses `credentials: 'include'` to send cookies automatically
86+
87+
**CORS Configuration:**
88+
89+
- `CORS_ALLOWED_ORIGINS` - Comma-separated list of allowed origins for credentialed CORS requests
90+
- Default: `*` (all origins allowed - not recommended for production with cookies)
91+
- Example: `CORS_ALLOWED_ORIGINS=https://example.com,https://admin.example.com`
92+
- Auth endpoint errors only reflect validated origins (security measure)
7593

7694
See [Authentication Roadmap](docs/enhancements/AUTHENTICATION_ROADMAP.md) for implementation details.
7795

@@ -356,12 +374,21 @@ data validation via WebSocket backend.
356374

357375
## Git Workflow
358376

359-
- Main branch: `master` (stable releases)
360-
- Development branch: `development` (testing)
361-
- Feature branches: Created for complex features
362-
- PRs should target `development` first, then merge to `master` after community testing
377+
- **Main branch:** `master` (stable releases)
378+
- **Development branch:** `development` (active development and testing)
379+
- **Feature branches:** Always branch off `development`, not `master`
380+
- **Pull requests:** Always target `development` branch, never `master` directly
381+
- **Release flow:** Changes merge from feature branches → `development``master` after community testing
363382
- Test locally before submitting PR
364383

384+
**Creating a feature branch:**
385+
386+
```bash
387+
git checkout development
388+
git pull origin development
389+
git checkout -b feature/your-feature-name
390+
```
391+
365392
## System Requirements
366393

367394
- PHP >= 8.4 (uses modern syntax like `array_find`)

0 commit comments

Comments
 (0)