docs: add AGENTS.md per module and unify ports to 70XX
- Add CLAUDE.md at root and AGENTS.md in apps/api, apps/indexer, apps/backoffice, crates/parsers with module-specific guidelines - Unify all service ports to 70XX (no more internal/external split): API 7080, Indexer 7081, Backoffice 7082 - Update docker-compose.yml, Dockerfiles, config.rs defaults, .env.example, backoffice routes, bench.sh, smoke.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
API_BASE_URL=http://localhost:8080
|
||||
API_BASE_URL=http://localhost:7080
|
||||
API_BOOTSTRAP_TOKEN=stripstream-dev-bootstrap-token
|
||||
NEXT_PUBLIC_API_BASE_URL=http://localhost:8080
|
||||
NEXT_PUBLIC_API_BASE_URL=http://localhost:7080
|
||||
NEXT_PUBLIC_API_BOOTSTRAP_TOKEN=stripstream-dev-bootstrap-token
|
||||
|
||||
66
apps/backoffice/AGENTS.md
Normal file
66
apps/backoffice/AGENTS.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# apps/backoffice — Interface d'administration (Next.js)
|
||||
|
||||
App Next.js 16 avec React 19, Tailwind CSS v4, TypeScript. Port de dev : **7082** (`npm run dev`).
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── layout.tsx # Layout global (nav sticky glassmorphism, ThemeProvider)
|
||||
├── page.tsx # Dashboard
|
||||
├── books/ # Liste et détail des livres
|
||||
├── libraries/ # Gestion bibliothèques
|
||||
├── jobs/ # Monitoring jobs
|
||||
├── tokens/ # Tokens API
|
||||
├── settings/ # Paramètres
|
||||
├── components/ # Composants métier
|
||||
│ ├── ui/ # Composants génériques (Button, Card, Badge, Icon, Input, ProgressBar, StatBox...)
|
||||
│ ├── BookCard.tsx
|
||||
│ ├── JobProgress.tsx
|
||||
│ ├── JobsList.tsx
|
||||
│ ├── LibraryForm.tsx
|
||||
│ ├── FolderBrowser.tsx / FolderPicker.tsx
|
||||
│ └── ...
|
||||
└── globals.css # Variables CSS, Tailwind base
|
||||
lib/
|
||||
└── api.ts # Client API : types DTO + fonctions fetch vers l'API Rust
|
||||
```
|
||||
|
||||
## Client API (lib/api.ts)
|
||||
|
||||
Tous les appels vers l'API Rust passent par `lib/api.ts`. Les types DTO sont définis là :
|
||||
- `LibraryDto`, `IndexJobDto`, `BookDto`, `TokenDto`, `FolderItem`
|
||||
|
||||
Ajouter les nouveaux endpoints et types dans ce fichier.
|
||||
|
||||
## Composants UI
|
||||
|
||||
Les composants génériques sont dans `app/components/ui/`. Utiliser ces composants plutôt que des éléments HTML bruts :
|
||||
|
||||
```tsx
|
||||
import { Button, Card, Badge, Icon, Input, ProgressBar, StatBox } from "@/app/components/ui";
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
- **App Router** : toutes les pages sont des Server Components par défaut. Utiliser `"use client"` seulement pour l'interactivité.
|
||||
- **Tailwind v4** : config dans `postcss.config.js` + `tailwind.config.js`. Variables CSS dans `globals.css`.
|
||||
- **Thème** : `ThemeProvider` + `ThemeToggle` pour dark/light mode via `next-themes`.
|
||||
- **Icônes** : composant `<Icon name="..." size="sm|md|lg" />` dans `ui/Icon.tsx` — pas de librairie externe.
|
||||
- **Navigation** : routes typées dans `layout.tsx` (`"/" | "/books" | "/libraries" | "/jobs" | "/tokens" | "/settings"`).
|
||||
|
||||
## Commandes
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # http://localhost:7082
|
||||
npm run build
|
||||
npm run start # Production sur http://localhost:7082
|
||||
```
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Port 7082** : pas le port Next.js par défaut (3000). Défini dans `package.json` scripts (`-p 7082`).
|
||||
- **API_BASE_URL** : en prod, configuré via env. En dev local, l'API doit tourner sur `http://localhost:7080`.
|
||||
- **React 19 + Next.js 16** : utiliser les nouvelles APIs (actions serveur, `use()` hook) si disponibles.
|
||||
- **Pas de gestion d'état global** : fetch direct depuis les Server Components ou `useState`/`useEffect` dans les Client Components.
|
||||
@@ -12,11 +12,11 @@ RUN npm run build
|
||||
FROM node:22-alpine AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=8082
|
||||
ENV PORT=7082
|
||||
ENV HOST=0.0.0.0
|
||||
RUN apk add --no-cache wget
|
||||
COPY --from=builder /app/.next/standalone ./
|
||||
COPY --from=builder /app/.next/static ./.next/static
|
||||
COPY --from=builder /app/public ./public
|
||||
EXPOSE 8082
|
||||
EXPOSE 7082
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
@@ -13,7 +13,7 @@ export async function GET(
|
||||
const quality = searchParams.get("quality") || "";
|
||||
|
||||
// Construire l'URL vers l'API backend
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiUrl = new URL(`${apiBaseUrl}/books/${bookId}/pages/${pageNum}`);
|
||||
apiUrl.searchParams.set("format", format);
|
||||
if (width) apiUrl.searchParams.set("width", width);
|
||||
|
||||
@@ -6,7 +6,7 @@ export async function GET(
|
||||
) {
|
||||
const { bookId } = await params;
|
||||
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiUrl = `${apiBaseUrl}/books/${bookId}/thumbnail`;
|
||||
|
||||
const token = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiToken = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
if (!apiToken) {
|
||||
|
||||
@@ -5,7 +5,7 @@ export async function POST(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await params;
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiToken = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
if (!apiToken) {
|
||||
|
||||
@@ -5,7 +5,7 @@ export async function GET(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await params;
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiToken = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
if (!apiToken) {
|
||||
|
||||
@@ -5,7 +5,7 @@ export async function GET(
|
||||
{ params }: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
const { id } = await params;
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiToken = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
if (!apiToken) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiToken = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
if (!apiToken) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NextRequest } from "next/server";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const apiBaseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const apiToken = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
if (!apiToken) {
|
||||
|
||||
@@ -6,7 +6,7 @@ export async function GET(
|
||||
) {
|
||||
try {
|
||||
const { key } = await params;
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const token = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
const response = await fetch(`${baseUrl}/settings/${key}`, {
|
||||
@@ -33,7 +33,7 @@ export async function POST(
|
||||
) {
|
||||
try {
|
||||
const { key } = await params;
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const token = process.env.API_BOOTSTRAP_TOKEN;
|
||||
const body = await request.json();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const token = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
const response = await fetch(`${baseUrl}/settings/cache/clear`, {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const token = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
const response = await fetch(`${baseUrl}/settings/cache/stats`, {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const token = process.env.API_BOOTSTRAP_TOKEN;
|
||||
|
||||
const response = await fetch(`${baseUrl}/settings`, {
|
||||
|
||||
@@ -90,7 +90,7 @@ export type SeriesDto = {
|
||||
};
|
||||
|
||||
function config() {
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:8080";
|
||||
const baseUrl = process.env.API_BASE_URL || "http://api:7080";
|
||||
const token = process.env.API_BOOTSTRAP_TOKEN;
|
||||
if (!token) {
|
||||
throw new Error("API_BOOTSTRAP_TOKEN is required for backoffice");
|
||||
|
||||
Reference in New Issue
Block a user