Labels für Stellen (Bewerbungen + Jobangebote), inkl. API & Swagger
Mehrere Labels pro Stelle (Regional, Remote-Deutschlandweit, Homeoffice-Deutschlandweit), gespeichert als JSON-Array in einer neuen labels-Spalte beider Tabellen (Migration). Geteiltes lib/labels.js mit parse/serialize; wiederverwendbare Partials fuer Chips + Mehrfachauswahl. - Web: setzen im Hinzufuegen-Modal, auf der Bearbeiten-Seite und im Jobangebot-Bearbeiten-Formular; Anzeige als Chips in den Listen. - Uebernahme eines Angebots traegt dessen Labels in die neue Bewerbung. - REST-API: labels[] in /applications und /joboffers (GET/POST/PUT), Filter ?label=…; OpenAPI/Swagger-Schemas + Enums erweitert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,14 @@ const STATUS_OPTIONS = [
|
||||
'Entwurf', 'Gesendet', 'Eingangsbestätigung', 'Vorstellungsgespräch',
|
||||
'Absage', 'Einstellung', 'Keine Rückmeldung',
|
||||
];
|
||||
const { LABEL_OPTIONS } = require('./labels');
|
||||
|
||||
// Reusable schema for the labels array (work-location labels of a Stelle).
|
||||
const labelsSchema = {
|
||||
type: 'array',
|
||||
items: { type: 'string', enum: LABEL_OPTIONS },
|
||||
description: 'Labels der Stelle (Arbeitsort). Mehrere möglich.',
|
||||
};
|
||||
|
||||
// Shared reusable schemas -----------------------------------------------
|
||||
|
||||
@@ -79,6 +87,7 @@ function buildOpenApiSpec(baseUrl = '') {
|
||||
{ name: 'year', in: 'query', schema: { type: 'string', pattern: '^[0-9]{4}$' }, description: 'Jahr (z. B. 2026)' },
|
||||
{ name: 'status', in: 'query', schema: { type: 'string', enum: STATUS_OPTIONS }, description: 'Filter nach Status' },
|
||||
{ name: 'art', in: 'query', schema: { type: 'string', enum: ART_OPTIONS }, description: 'Filter nach Bewerbungsart' },
|
||||
{ name: 'label', in: 'query', schema: { type: 'string', enum: LABEL_OPTIONS }, description: 'Filter nach Label (Stellen mit diesem Label)' },
|
||||
{ name: 'search', in: 'query', schema: { type: 'string' }, description: 'Freitextsuche in Firma und Stelle' },
|
||||
{ name: 'limit', in: 'query', schema: { type: 'integer', minimum: 1, maximum: 500, default: 100 }, description: 'Max. Anzahl Ergebnisse' },
|
||||
{ name: 'offset', in: 'query', schema: { type: 'integer', minimum: 0, default: 0 }, description: 'Ergebnis-Offset (Paging)' },
|
||||
@@ -663,6 +672,7 @@ function buildOpenApiSpec(baseUrl = '') {
|
||||
stelle: { type: 'string' },
|
||||
art: { type: 'string', enum: ART_OPTIONS, nullable: true },
|
||||
status: { type: 'string', enum: STATUS_OPTIONS, nullable: true },
|
||||
labels: { ...labelsSchema, nullable: true },
|
||||
notizen: { type: 'string', nullable: true },
|
||||
interne_notizen: { type: 'string', nullable: true },
|
||||
ort: { type: 'string', nullable: true },
|
||||
@@ -692,6 +702,7 @@ function buildOpenApiSpec(baseUrl = '') {
|
||||
stelle: { type: 'string' },
|
||||
art: { type: 'string', enum: ART_OPTIONS },
|
||||
status: { type: 'string', enum: STATUS_OPTIONS },
|
||||
labels: labelsSchema,
|
||||
notizen: { type: 'string' },
|
||||
interne_notizen: { type: 'string' },
|
||||
ort: { type: 'string' },
|
||||
@@ -711,6 +722,7 @@ function buildOpenApiSpec(baseUrl = '') {
|
||||
stelle: { type: 'string' },
|
||||
art: { type: 'string', enum: ART_OPTIONS },
|
||||
status: { type: 'string', enum: STATUS_OPTIONS },
|
||||
labels: labelsSchema,
|
||||
notizen: { type: 'string' },
|
||||
interne_notizen: { type: 'string' },
|
||||
ort: { type: 'string' },
|
||||
@@ -871,6 +883,7 @@ function buildOpenApiSpec(baseUrl = '') {
|
||||
anzeige_datum: { type: 'string', format: 'date', nullable: true, description: 'Datum der eigentlichen Stellenanzeige (vom Drittanbieter übergeben)' },
|
||||
kontakt_email: { type: 'string', format: 'email', nullable: true, description: 'Kontakt-E-Mail-Adresse der Stelle' },
|
||||
status: { type: 'string', enum: ['offen', 'uebernommen', 'abgelehnt'] },
|
||||
labels: { ...labelsSchema, nullable: true },
|
||||
verknuepfte_bewerbung_id: { type: 'integer', nullable: true },
|
||||
url_norm: { type: 'string', nullable: true, description: 'Normalisierte URL für die De-Duplizierung (serverseitig gesetzt)' },
|
||||
created_at: { type: 'string', format: 'date-time' },
|
||||
@@ -895,6 +908,7 @@ function buildOpenApiSpec(baseUrl = '') {
|
||||
anzeige_datum: { type: 'string', format: 'date', description: 'Datum der eigentlichen Stellenanzeige (ISO YYYY-MM-DD)' },
|
||||
kontakt_email: { type: 'string', format: 'email', description: 'Kontakt-E-Mail-Adresse der Stelle' },
|
||||
status: { type: 'string', enum: ['offen', 'uebernommen', 'abgelehnt'], default: 'offen' },
|
||||
labels: labelsSchema,
|
||||
},
|
||||
},
|
||||
JobOfferResult: {
|
||||
|
||||
Reference in New Issue
Block a user