Initial commit

This commit is contained in:
2026-05-05 10:39:43 +02:00
commit b590ecdc35
87 changed files with 3934 additions and 0 deletions
+490
View File
@@ -0,0 +1,490 @@
# MetaCourse API — Frontend Integration Guide
> Target stack: Angular + Capacitor
> Base URL (local): `http://localhost:8080`
> Base URL (production): `http://romaric-thibault.fr`
---
## Deployment
### Requirements
- Docker + Docker Compose installed on the server
### Start the stack
```bash
docker compose up -d --build
```
The API will be available on port **8080**. SQL Server runs on port **1433** (internal). Migrations run automatically on startup.
### Swagger UI
```
http://<host>:8080/swagger
```
---
## Authentication
There is **no JWT** currently. Login returns user info directly. Store `UserId` in local storage / Capacitor Preferences to identify the current user across requests.
---
## Data Models (TypeScript interfaces)
```typescript
// Enums
type CourseStatus = 'Draft' | 'Published';
type ResourceType = 'Url' | 'Video' | 'Text' | 'File';
interface User {
id: string; // Guid
name: string;
email: string;
createdAt: string; // ISO date
}
interface LoginResponse {
userId: string;
name: string;
email: string;
}
interface Course {
id: string;
title: string;
description: string;
status: CourseStatus;
creatorId: string;
creatorName: string;
topicCount: number;
createdAt: string;
updatedAt: string;
}
interface CourseDetails extends Course {
topics: Topic[];
}
interface Topic {
id: string;
title: string;
description?: string;
position: number;
courseId: string;
resources: Resource[];
}
interface Resource {
id: string;
type: ResourceType;
title: string;
content: string; // URL, video URL, text body, or file path
createdAt: string;
}
interface Enrollment {
userId: string;
courseId: string;
courseTitle: string;
enrolledAt: string;
completedAt?: string;
}
interface CourseProgress {
courseId: string;
userId: string;
totalTopics: number;
completedTopics: number;
totalResources: number;
completedResources: number;
progressPercentage: number; // 0.0 - 100.0
}
```
---
## API Endpoints
### Users
#### Register
```
POST /api/users/register
```
**Body:**
```json
{
"name": "Alice",
"email": "alice@example.com",
"password": "Password1"
}
```
**Validation:** name 2100 chars, valid email, password ≥8 chars + 1 uppercase + 1 digit
**Response:** `201``User`
**Errors:** `400` validation | `409` email already taken
---
#### Login
```
POST /api/users/login
```
**Body:**
```json
{
"email": "alice@example.com",
"password": "Password1"
}
```
**Response:** `200``LoginResponse`
**Errors:** `401` wrong credentials
---
#### Get User Profile
```
GET /api/users/{id}
```
**Response:** `200``User` | `404`
---
### Courses
#### List Published Courses
```
GET /api/courses
```
Optional query param: `?search=angular`
**Response:** `200``Course[]` (only Published courses, newest first)
---
#### Get Course with Topics & Resources
```
GET /api/courses/{id}
```
**Response:** `200``CourseDetails` | `404`
---
#### Create Course
```
POST /api/courses
```
**Body:**
```json
{
"title": "Introduction to Angular",
"description": "Learn Angular from scratch",
"creatorId": "<userId>"
}
```
**Response:** `201``Course` (status = `Draft`)
---
#### Update Course
```
PUT /api/courses/{id}
```
**Body:**
```json
{
"id": "<courseId>",
"title": "Updated Title",
"description": "Updated description"
}
```
**Response:** `200``Course` | `404`
---
#### Publish Course
```
PATCH /api/courses/{id}/publish
```
**Response:** `200``Course` | `422` if no topics yet | `404`
---
#### Delete Course
```
DELETE /api/courses/{id}
```
**Response:** `204` | `409` if course has enrollments | `404`
---
#### Courses Created by a User
```
GET /api/users/{userId}/courses
```
**Response:** `200``Course[]`
---
### Topics
#### Get Topic
```
GET /api/topics/{id}
```
**Response:** `200``Topic` (includes resources ordered by position) | `404`
---
#### Create Topic
```
POST /api/topics
```
**Body:**
```json
{
"courseId": "<courseId>",
"title": "Components",
"description": "Optional description",
"position": 1
}
```
**Response:** `201``Topic`
---
#### Update Topic
```
PUT /api/topics/{id}
```
**Body:**
```json
{
"id": "<topicId>",
"title": "Updated Title",
"description": "Updated",
"position": 2
}
```
**Response:** `200``Topic` | `404`
---
#### Delete Topic
```
DELETE /api/topics/{id}
```
**Response:** `204` | `404`
---
#### Link Resource to Topic
```
POST /api/topics/{topicId}/resources/{resourceId}
```
**Body:**
```json
{ "position": 1 }
```
**Response:** `204`
---
#### Unlink Resource from Topic
```
DELETE /api/topics/{topicId}/resources/{resourceId}
```
**Response:** `204`
---
### Resources
#### List All Resources
```
GET /api/resources
```
**Response:** `200``Resource[]` (ordered by creation date desc)
---
#### Get Resource
```
GET /api/resources/{id}
```
**Response:** `200``Resource` | `404`
---
#### Create Resource
```
POST /api/resources
```
**Body:**
```json
{
"type": "Url",
"title": "Angular Docs",
"content": "https://angular.io"
}
```
**Types & content:**
| Type | content field |
|------|--------------|
| `Url` | Full URL (https required) |
| `Video` | Video URL (https required) |
| `Text` | Markdown or plain text body |
| `File` | File path or download URL |
**Response:** `201``Resource`
---
#### Update Resource
```
PUT /api/resources/{id}
```
**Body:**
```json
{
"id": "<resourceId>",
"type": "Video",
"title": "Updated",
"content": "https://youtube.com/..."
}
```
**Response:** `200``Resource` | `404`
---
#### Delete Resource
```
DELETE /api/resources/{id}
```
**Response:** `204` | `404`
---
### Enrollments
#### Enroll in a Course
```
POST /api/courses/{courseId}/enroll
```
**Body:**
```json
{
"userId": "<userId>",
"courseId": "<courseId>"
}
```
**Response:** `201``Enrollment`
**Errors:** `409` already enrolled | `422` course not Published | `404`
---
#### User's Enrollments
```
GET /api/users/{userId}/enrollments
```
**Response:** `200``Enrollment[]`
---
### Progress
#### Mark Topic Progress
```
POST /api/topics/{topicId}/progress
```
**Body:**
```json
{
"userId": "<userId>",
"topicId": "<topicId>",
"completed": true
}
```
**Response:** `204` (upsert — safe to call multiple times)
---
#### Mark Resource Progress
```
POST /api/resources/{resourceId}/progress
```
**Body:**
```json
{
"userId": "<userId>",
"resourceId": "<resourceId>",
"completed": true
}
```
**Response:** `204` (upsert)
---
#### Get Course Progress
```
GET /api/courses/{courseId}/progress?userId={userId}
```
**Response:** `200``CourseProgress`
```json
{
"courseId": "...",
"userId": "...",
"totalTopics": 5,
"completedTopics": 3,
"totalResources": 10,
"completedResources": 7,
"progressPercentage": 66.67
}
```
---
## Error Response Format
All validation and business errors follow this shape:
```json
{
"statusCode": 400,
"errors": {
"email": ["'Email' is not a valid email address."],
"password": ["Password must be at least 8 characters."]
}
}
```
---
## CORS
All origins, methods, and headers are allowed (`AllowAll` policy). No special headers needed from Angular/Capacitor.
---
## Typical User Flow (Angular/Capacitor)
```
1. POST /api/users/register → store userId in Capacitor Preferences
2. POST /api/users/login → verify credentials
3. GET /api/courses → show published course catalog
4. GET /api/courses/{id} → show course detail with topics
5. POST /api/courses/{id}/enroll → enroll user
6. GET /api/users/{id}/enrollments → show My Courses
7. POST /api/topics/{id}/progress → mark topic done
8. POST /api/resources/{id}/progress → mark resource done
9. GET /api/courses/{id}/progress?userId=... → show progress bar
```
---
## Notes for Angular Service Layer
- All IDs are **UUIDs (string)** — no integer IDs.
- Dates are **ISO 8601 UTC strings** — use `new Date(dateString)` or a pipe.
- `progressPercentage` is a `number` (float 0100), round for display.
- `status` and `type` come back as **strings**, not numbers.
- No auth headers needed currently — all endpoints are `AllowAnonymous`.