Skip to content

Commit 8378937

Browse files
committed
docs: initial content for Flutter News App documentation
- Added overview pages for API endpoints and deployment guides - Included local setup instructions for API server, web dashboard, and mobile client - Covered web dashboard features including authentication, content management, and app configuration - Provided API reference for data endpoints
1 parent 77ced50 commit 8378937

19 files changed

+1025
-36
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: 'Advanced: Dependency Injection'
3+
description: An explanation of the API server's service layer and dependency injection pattern.
4+
---
5+
6+
import { Steps, Aside, Tabs, TabItem } from '@astrojs/starlight/components';
7+
8+
The API server is built with a clean, layered architecture that separates concerns and promotes testability. At the heart of this design is the use of a service layer and a centralized dependency injection (DI) mechanism.
9+
10+
## The `AppDependencies` Singleton
11+
12+
The `AppDependencies` class (`lib/src/config/app_dependencies.dart`) is a singleton responsible for initializing and providing access to all major application-wide dependencies.
13+
14+
When the server first starts, the `init()` method on this singleton is called. It performs several critical setup tasks in order:
15+
16+
1. **Initializes the Database Connection:** Establishes a connection to the MongoDB instance specified in the environment variables.
17+
2. **Seeds the Database:** Runs a seeding service to populate the database with initial data (countries, topics, etc.) if it doesn't already exist.
18+
3. **Initializes Data Clients:** Creates instances of the `DataMongodb` clients for each data model. These clients are the lowest-level components that directly interact with the database.
19+
4. **Initializes Repositories:** Wraps each data client in a `DataRepository`. Repositories provide a clean abstraction layer over the data clients.
20+
5. **Initializes Services:** Creates instances of all core business logic services (e.g., `AuthService`, `DashboardSummaryService`), injecting the repositories and other services they depend on.
21+
22+
<Aside type="info">
23+
This centralized initialization ensures that all dependencies are ready before the server begins accepting requests and that the dependency graph is correctly resolved.
24+
</Aside>
25+
26+
## Dependency Injection in Requests
27+
28+
Once initialized, these dependencies are made available to every incoming request using Dart Frog's middleware and provider system.
29+
30+
The root middleware (`/routes/_middleware.dart`) is responsible for this. For each request, it:
31+
32+
1. Ensures `AppDependencies.instance.init()` has been called.
33+
2. Uses a series of `.use(provider<T>((_) => deps.dependency))` calls to inject each repository and service from the `AppDependencies` singleton into the request context.
34+
35+
### Accessing Dependencies in Route Handlers
36+
37+
Because of this DI setup, any route handler or downstream middleware can easily access a required dependency by calling `context.read<T>()`.
38+
39+
**Example:**
40+
```dart title="A route handler"
41+
// Read the AuthService provided by the root middleware
42+
final authService = context.read<AuthService>();
43+
44+
// Now you can use the service
45+
final result = await authService.performAnonymousSignIn();
46+
```
47+
48+
This pattern decouples the route handlers from the concrete implementation of the services they use, making the code cleaner, more modular, and significantly easier to test.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
title: 'Advanced: Middleware'
3+
description: An explanation of the API server's middleware architecture and request lifecycle.
4+
---
5+
6+
import { Steps, Aside } from '@astrojs/starlight/components';
7+
8+
The API server uses a layered middleware architecture to handle requests. Middleware are functions that process a request before it reaches its final destination (the route handler). This approach allows for the separation of concerns like logging, authentication, and error handling from the core business logic.
9+
10+
## Request Lifecycle
11+
12+
An incoming request to the API server flows through a series of middleware in an "onion-skin" fashion. The outermost middleware runs first, and the innermost middleware runs last, just before the route handler.
13+
14+
Here is the typical execution order for a request to a protected data endpoint like `/api/v1/data?model=headline`:
15+
16+
<Steps>
17+
1. **Root Middleware (`/routes/_middleware.dart`)**
18+
- **Dependency Injection:** Initializes and provides all application-wide dependencies (repositories, services, etc.) into the request context. This happens once per request.
19+
- **Request ID Generation:** Assigns a unique ID to the request for logging and traceability.
20+
- **Request Logger:** Logs the incoming request details.
21+
- **Error Handler:** This is the outermost layer, wrapping the entire request to catch any exceptions thrown by inner layers and format them into a standardized JSON error response.
22+
23+
2. **API v1 Middleware (`/routes/api/v1/_middleware.dart`)**
24+
- **CORS Handling:** Applies Cross-Origin Resource Sharing (CORS) headers to the response, allowing the web dashboard to communicate with the API.
25+
- **Authentication Provider:** Checks for a `Bearer` token in the `Authorization` header. If present, it validates the token and injects the corresponding `User` object (or `null`) into the request context.
26+
27+
3. **Data Route Middleware (`/routes/api/v1/data/_middleware.dart`)**
28+
- **Require Authentication:** Checks if a `User` object exists in the context. If not, it immediately aborts the request with a `401 Unauthorized` error.
29+
- **Model Validation:** Validates the `?model=` query parameter and injects the corresponding `ModelConfig` into the context.
30+
- **Authorization:** Checks if the authenticated user has the required permissions to perform the requested action on the specified model. If not, it aborts with a `403 Forbidden` error.
31+
32+
4. **Route Handler (`/routes/api/v1/data/index.dart` or `[id].dart`)**
33+
- Finally, if all middleware checks pass, the request reaches the route handler, which contains the core business logic for the endpoint (e.g., fetching data from a repository and returning it).
34+
</Steps>
35+
36+
This layered approach ensures that by the time a request reaches its route handler, it has been logged, authenticated, authorized, and has all necessary dependencies available via the request context.

src/content/docs/advanced/rbac.mdx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
title: 'Advanced: Role-Based Access Control (RBAC)'
3+
description: An explanation of the API server's permission and role system.
4+
---
5+
6+
import { Steps, Aside, Tabs, TabItem } from '@astrojs/starlight/components';
7+
8+
The API server implements a robust Role-Based Access Control (RBAC) system to secure its endpoints and data. This system ensures that users can only perform actions and access data that they are explicitly permitted to.
9+
10+
## Core Concepts
11+
12+
### Roles
13+
14+
Every user in the system has two distinct roles that define their capabilities:
15+
16+
- **`appRole`**: Governs permissions within the mobile application.
17+
- `guestUser`: An anonymous user.
18+
- `standardUser`: A registered user.
19+
- `premiumUser`: A user with a premium subscription.
20+
- **`dashboardRole`**: Governs permissions for the web-based content management dashboard.
21+
- `none`: No access to the dashboard.
22+
- `publisher`: Can manage content like headlines.
23+
- `admin`: Has full administrative access.
24+
25+
### Permissions
26+
27+
Permissions are granular strings that represent a specific action on a specific resource, following a `resource.action` format.
28+
29+
**Example:** `headline.create`, `user.read_owned`
30+
31+
### The `PermissionService`
32+
33+
This is the central service responsible for authorization checks. It determines a user's total permissions by combining the permissions granted by their `appRole` and `dashboardRole`. Administrators (`dashboardRole: admin`) are automatically granted all permissions.
34+
35+
## Permission Mapping
36+
37+
The `model_registry.dart` file is the single source of truth for mapping API actions (HTTP methods on specific models) to required permissions.
38+
39+
<Aside type="note">
40+
This centralized registry allows for easy auditing and modification of access control rules without changing the core logic of the route handlers.
41+
</Aside>
42+
43+
Here's how it works for the generic `/api/v1/data` endpoint:
44+
45+
1. A request comes in, e.g., `POST /api/v1/data?model=headline`.
46+
2. The middleware identifies the model (`headline`) and the method (`POST`).
47+
3. It looks up the `headline` configuration in the `modelRegistry`.
48+
4. It finds the permission required for the `postPermission` action, which is `adminOnly`.
49+
5. It uses the `PermissionService` to check if the authenticated user has the `admin` role.
50+
6. If the check fails, the request is rejected with a `403 Forbidden` error.
51+
52+
### Ownership Checks
53+
54+
For user-owned data (like `user_app_settings`), the registry also specifies when an ownership check is required. If a user tries to `GET /api/v1/data/some_other_user_id?model=user_app_settings`, the `ownershipCheckMiddleware` will intervene. It fetches the item, compares its owner ID to the authenticated user's ID, and rejects the request if they don't match (unless the user is an admin).
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
---
2+
title: 'API Reference: Authentication'
3+
description: Detailed documentation for the authentication endpoints.
4+
---
5+
6+
import { Steps, Tabs, TabItem, Aside } from '@astrojs/starlight/components';
7+
8+
This section provides a detailed reference for all authentication-related endpoints.
9+
10+
## Endpoints
11+
12+
### Anonymous Sign-In
13+
14+
Creates a new anonymous guest user account. This is typically the first call an app makes on a fresh install to allow users to interact with the app before creating a permanent account.
15+
16+
**Endpoint:** `POST /api/v1/auth/anonymous`
17+
18+
**Authentication:** None required.
19+
20+
#### Success Response (200 OK)
21+
22+
Returns a `SuccessApiResponse` containing an `AuthSuccessResponse` payload with the new anonymous `User` object and a JWT `token`.
23+
24+
<Tabs>
25+
<TabItem label="Payload">
26+
```json
27+
{
28+
"data": {
29+
"user": {
30+
"id": "66a21e2a77f294e7a1f7d41a",
31+
"email": "[email protected]",
32+
"appRole": "guestUser",
33+
"dashboardRole": "none",
34+
"createdAt": "2024-07-25T09:30:18.000Z",
35+
"feedActionStatus": {
36+
// ... default statuses
37+
}
38+
},
39+
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
40+
},
41+
"metadata": {
42+
// ...
43+
}
44+
}
45+
```
46+
</TabItem>
47+
</Tabs>
48+
49+
---
50+
51+
### Request Sign-In Code
52+
53+
Initiates the passwordless sign-in/sign-up process by sending a one-time verification code to the user's email.
54+
55+
**Endpoint:** `POST /api/v1/auth/request-code`
56+
57+
**Authentication:** None required.
58+
59+
#### Request Body
60+
61+
<Tabs>
62+
<TabItem label="Standard Sign-In">
63+
```json
64+
{
65+
"email": "[email protected]"
66+
}
67+
```
68+
</TabItem>
69+
<TabItem label="Dashboard Login">
70+
```json
71+
{
72+
"email": "[email protected]",
73+
"isDashboardLogin": true
74+
}
75+
```
76+
</TabItem>
77+
</Tabs>
78+
79+
- `email` (string, required): The user's email address.
80+
- `isDashboardLogin` (boolean, optional): When `true`, the server first verifies the user exists and has the necessary permissions (`admin` or `publisher`) before sending a code. Defaults to `false`.
81+
82+
#### Success Response (202 Accepted)
83+
84+
An empty body with a `202 Accepted` status code indicates the request was successful and the email is being sent.
85+
86+
#### Error Responses
87+
88+
- `400 Bad Request`: If the email format is invalid or the request body is malformed.
89+
- `401 Unauthorized`: If `isDashboardLogin` is true and the user does not exist.
90+
- `403 Forbidden`: If `isDashboardLogin` is true and the user exists but lacks dashboard permissions.
91+
92+
---
93+
94+
### Verify Sign-In Code
95+
96+
Completes the sign-in process by verifying the email and code. This single endpoint handles multiple scenarios:
97+
98+
- Standard user sign-in.
99+
- New user sign-up.
100+
- Converting an anonymous guest user to a permanent account.
101+
- Dashboard user login.
102+
103+
**Endpoint:** `POST /api/v1/auth/verify-code`
104+
105+
**Authentication:**
106+
- **Optional:** If a guest user is converting their account, include their anonymous JWT `Bearer` token in the `Authorization` header.
107+
- **None:** For standard sign-in/sign-up flows.
108+
109+
#### Request Body
110+
111+
```json
112+
{
113+
"email": "[email protected]",
114+
"code": "123456",
115+
"isDashboardLogin": false
116+
}
117+
```
118+
119+
- `email` (string, required): The user's email address.
120+
- `code` (string, required): The 6-digit verification code sent to the user's email.
121+
- `isDashboardLogin` (boolean, optional): Must be `true` if verifying a code for dashboard access. Defaults to `false`.
122+
123+
#### Success Response (200 OK)
124+
125+
Returns a `SuccessApiResponse` containing an `AuthSuccessResponse` payload with the authenticated `User` object and a new JWT `token`.
126+
127+
#### Error Responses
128+
129+
- `400 Bad Request`: If the code is invalid, expired, or the request body is malformed.
130+
- `403 Forbidden`: If `isDashboardLogin` is true and the user lacks dashboard permissions.
131+
132+
---
133+
134+
### Get Current User
135+
136+
Retrieves the full profile of the currently authenticated user.
137+
138+
**Endpoint:** `GET /api/v1/auth/me`
139+
140+
**Authentication:** Required. A valid JWT `Bearer` token must be provided.
141+
142+
#### Success Response (200 OK)
143+
144+
Returns a `SuccessApiResponse` containing the `User` object.
145+
146+
<Tabs>
147+
<TabItem label="Payload">
148+
```json
149+
{
150+
"data": {
151+
"id": "66a21e2a77f294e7a1f7d41a",
152+
"email": "[email protected]",
153+
"appRole": "standardUser",
154+
"dashboardRole": "none",
155+
// ... other user fields
156+
},
157+
"metadata": {
158+
// ...
159+
}
160+
}
161+
```
162+
</TabItem>
163+
</Tabs>
164+
165+
#### Error Responses
166+
167+
- `401 Unauthorized`: If the token is missing, invalid, or expired.
168+
169+
---
170+
171+
### Sign Out
172+
173+
Performs server-side sign-out actions, primarily invalidating the current JWT to prevent its reuse.
174+
175+
**Endpoint:** `POST /api/v1/auth/sign-out`
176+
177+
**Authentication:** Required. A valid JWT `Bearer` token must be provided.
178+
179+
#### Success Response (204 No Content)
180+
181+
An empty body with a `204 No Content` status code indicates successful sign-out.
182+
183+
#### Error Responses
184+
185+
- `401 Unauthorized`: If the token is missing, invalid, or expired.
186+
187+
---
188+
189+
### Delete Account
190+
191+
Permanently deletes the authenticated user's account and all associated data (settings, preferences, etc.).
192+
193+
**Endpoint:** `DELETE /api/v1/auth/delete-account`
194+
195+
**Authentication:** Required. A valid JWT `Bearer` token must be provided.
196+
197+
#### Success Response (204 No Content)
198+
199+
An empty body with a `204 No Content` status code indicates successful account deletion.
200+
201+
#### Error Responses
202+
203+
- `401 Unauthorized`: If the token is missing, invalid, or expired.
204+
- `404 Not Found`: If the user to be deleted does not exist.

0 commit comments

Comments
 (0)