Content Service
Repo: o-apps/content-service (fluxcd app directory: content-api) · Port: 2088
A general-purpose CMS/community backend: articles, blog posts, documents, videos, and a discussion forum, backed by S3-compatible object storage for file uploads.
Key Capabilities
- Articles & blog — CRUD for articles; blog posts additionally support slugs, categories, and a view counter
- Documents & videos — upload, list, get, download, and delete, with presigned S3 URLs for downloads (expiry configurable via
PRESIGN_EXPIRY_SECONDS) - Forum — posts and threaded replies, upvoting, "accept answer," and per-course/per-user post listings — the course-context fields suggest this backs discussion threads tied to course-service content
- Image uploads — a dedicated endpoint for inline image uploads (e.g. for article/blog body content)
Auth
A single API_KEY gates every route uniformly (router.Use(authMiddleware.Handler) applied globally, before any route registration) — there's no split between public and admin routes the way customer-service has for its contact form.
REST API
| Method | Path | Description |
|---|---|---|
POST | GET | PUT | DELETE | /articles, /articles/{id} | Article CRUD |
POST | GET | PUT | DELETE | /blogs, /blogs/{id} | Blog post CRUD |
GET | /blogs/slug/{slug} | Get a blog post by slug |
GET | /blogs/category/{category} | List by category |
POST | /blogs/slug/{slug}/views | Increment view count |
POST | GET | DELETE | /documents, /documents/{id} | Document CRUD |
GET | /documents/{id}/download | Presigned download URL |
POST | GET | PUT | DELETE | /videos, /videos/{id} | Video CRUD |
GET | /videos/{id}/download | Presigned download URL |
POST | /upload/image | Inline image upload |
POST | GET | PUT | DELETE | /forum/posts, /forum/posts/{postId} | Forum post CRUD |
POST | /forum/posts/{postId}/views | /upvote | View count / upvote |
GET | /forum/posts/course/{courseId} | /user/{userId} | /search | Filtered post listings |
POST | GET | PUT | DELETE | /forum/replies, /forum/replies/{replyId} | Reply CRUD |
GET | /forum/posts/{postId}/replies | Replies for a post |
POST | /forum/replies/{replyId}/upvote | Upvote a reply |
POST | /forum/posts/{postId}/accept/{replyId} | Accept a reply as the answer |
GET | /health | Health check (unauthenticated) |
GET | /docs, /swagger | Swagger UI |
Environment Variables
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection — required, no fallback |
API_KEY | Shared secret every route requires |
AWS_REGION | Default: eu-north-1 |
AWS_S3_BUCKET | Defaults to <environment>-kubeopera-content-service |
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY | S3 credentials |
AWS_USE_STATIC_CREDS | Use static credentials instead of the instance/pod role |
PRESIGN_EXPIRY_SECONDS | Download URL expiry (default: 900) |
HTTP_PORT | HTTP port (default: 2088) |