CommunityPro / CommunityPro/community-pro-api

Content: public read endpoints, Meilisearch posts index, ISR revalidation (Phase 4.4)

Open
#5 0 comments 0 reactions 0 assignees View on GitHub
content
Dominant language
C#
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Scope
Public read surface + search sync + frontend cache invalidation for the blog.

## Endpoints (anonymous)
| Method | Path | Notes |
|---|---|---|
| GET | `/posts` | **published only**, tag filter, paginated, newest first |
| GET | `/posts/{slug}` | published only; feeds the ISR post page |
| GET | `/posts/featured` | the single featured published post |

## Meilisearch `posts` index
- Follow the `CommunityPro.Search` module patterns exactly (hand-rolled REST client, index+settings ensured at boot, sync-on-write handler that logs failures and never throws).
- Document shape mirrors public card data only: id, slug, title, excerpt, tags, authorId, publishedAt. Searchable: `title, excerpt, tags`; filterable: `tags`; sortable: `publishedAt`. **Never index drafts/submitted/rejected posts — publish adds, unpublish/reject removes.**
- Extend the existing `reindex` command (`dotnet run -- reindex`) to rebuild `posts` alongside `members` in 500-doc batches.

## ISR revalidation
On `PostPublished`: `POST {FRONTEND_URL}/api/revalidate?tag=post-{slug}` with a shared secret header (`REVALIDATE_SECRET` — treat like any credential). Best-effort with logging; never fail the pipeline.

## Error codes
`content.not_found`, `search.unavailable` (degrade like members search does)

## Dependencies
Blocked by #3; consumes the `PostPublished` event emitted by #4.

## Acceptance criteria
- [ ] Unpublished posts are unreachable via every public endpoint and absent from the index (query-level filtering, tested)
- [ ] `PostPublished` handler upserts the search doc; failure is logged, not thrown
- [ ] Revalidation call sends the secret and swallows/logs failures
- [ ] `reindex` rebuilds posts (test via the existing search fakes)

### Conventions (project-wide, non-negotiable)
- .NET 9, records for immutable shapes, file-scoped namespaces, primary constructors where they read well. Minimal-API endpoints grouped per module via `IEndpointModule.MapEndpoints`.
- `Result` (SharedKernel) instead of exception-driven control flow. Endpoint results map failures to ProblemDetails with the stable error codes listed above — the frontend keys off them.
- Module owns its EF Core `DbContext` mapped to its own Postgres schema. Modules never reference each other's internals — cross-module needs go through a public contract interface or an in-process domain event (`IEventPublisher`).
- All external calls (GitHub, Stripe, Brevo, Cloudinary, Meilisearch) behind interfaces owned by the consuming module.
- Every list endpoint paginated (offset is fine). xUnit tests in `tests/CommunityPro.Tests//` following the existing harness patterns (see `Members/MembersTestHarness.cs`).

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with the CommunityPro.Search module patterns, the existing reindex command, and tests using the existing search fakes; Members/MembersTestHarness.cs shows the project’s test harness conventions. Trace the PostPublished event emitted by #4 and the public endpoint grouping conventions. Done means all acceptance criteria pass, including filtering unpublished posts, resilient sync and revalidation, stable error codes, and batched reindexing.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, postgres
Domain
api, backend, databases, frontend, search
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.