Baustein 5: Praxisaufgaben mit Anhaengen und Abnahme
- Status offen / in Arbeit / zur Abnahme / abgenommen, mit Zeitstempeln - Notizfeld fuer den Azubi, Dateianhaenge bis 25 MB - Speicherpfad nur aus selbst erzeugter UUID, nie aus dem Dateinamen - Auslieferung ueber /anhaenge/<kennung> mit Rechtepruefung bei jedem Abruf, CSP sandbox und nosniff; SVG ausdruecklich nicht erlaubt - Anhaenge haengen an Aufgabe UND Azubi - Ausbilder hakt Kriterien einzeln ab, Note und Rueckmeldung, Abnahme sperrt - Zurueckgeben zur Nacharbeit - "Was auf dich wartet" zeigt offene Abnahmen - Abgenommene Aufgaben zaehlen im Wochenfortschritt mit Behoben: Next.js deckelt Serveraktionen ab Werk bei 1 MB - damit waere kein Handyfoto durchgekommen. bodySizeLimit jetzt 30 MB, Vorabpruefung im Browser, client_max_body_size im Proxy-Beispiel auf 30m. Geaendert: Seiten verweigern fremde Daten mit 404 statt mit einem Fehler. Eigene Seiten fuer "Nicht gefunden" und Stoerfaelle. 24 neue Tests, insgesamt 157. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bb592ad2bd
commit
ffbca01bdc
+63
-1
@@ -124,6 +124,56 @@ export const kartenVerlauf = sqliteTable(
|
||||
(t) => [index('karten_verlauf_benutzer_idx').on(t.benutzerId, t.bewertetAm)],
|
||||
);
|
||||
|
||||
export const aufgabenStatus = ['offen', 'in_arbeit', 'zur_abnahme', 'abgenommen'] as const;
|
||||
export type AufgabenStatus = (typeof aufgabenStatus)[number];
|
||||
|
||||
export const aufgabeStatus = sqliteTable(
|
||||
'aufgabe_status',
|
||||
{
|
||||
id: text('id').primaryKey(),
|
||||
benutzerId: text('benutzer_id')
|
||||
.notNull()
|
||||
.references(() => benutzer.id, { onDelete: 'cascade' }),
|
||||
aufgabeId: text('aufgabe_id').notNull(),
|
||||
status: text('status', { enum: aufgabenStatus }).notNull().default('offen'),
|
||||
notiz: text('notiz').notNull().default(''),
|
||||
kriterienErfuellt: text('kriterien_erfuellt').notNull().default('[]'),
|
||||
bewertung: text('bewertung'),
|
||||
rueckmeldung: text('rueckmeldung'),
|
||||
begonnenAm: text('begonnen_am'),
|
||||
abgegebenAm: text('abgegeben_am'),
|
||||
abgenommenVon: text('abgenommen_von').references(() => benutzer.id),
|
||||
abgenommenAm: text('abgenommen_am'),
|
||||
geaendertAm: text('geaendert_am').notNull(),
|
||||
},
|
||||
(t) => [
|
||||
uniqueIndex('aufgabe_status_idx').on(t.benutzerId, t.aufgabeId),
|
||||
index('aufgabe_status_status_idx').on(t.status),
|
||||
],
|
||||
);
|
||||
|
||||
export const bezugTypen = ['aufgabe', 'checkliste', 'bericht'] as const;
|
||||
export type BezugTyp = (typeof bezugTypen)[number];
|
||||
|
||||
export const anhang = sqliteTable(
|
||||
'anhang',
|
||||
{
|
||||
id: text('id').primaryKey(),
|
||||
bezugTyp: text('bezug_typ', { enum: bezugTypen }).notNull(),
|
||||
bezugId: text('bezug_id').notNull(),
|
||||
benutzerId: text('benutzer_id')
|
||||
.notNull()
|
||||
.references(() => benutzer.id, { onDelete: 'cascade' }),
|
||||
dateiname: text('dateiname').notNull(),
|
||||
mimeTyp: text('mime_typ').notNull(),
|
||||
groesse: integer('groesse').notNull(),
|
||||
pfad: text('pfad').notNull(),
|
||||
beschriftung: text('beschriftung'),
|
||||
hochgeladenAm: text('hochgeladen_am').notNull(),
|
||||
},
|
||||
(t) => [index('anhang_bezug_idx').on(t.bezugTyp, t.bezugId), index('anhang_benutzer_idx').on(t.benutzerId)],
|
||||
);
|
||||
|
||||
export type Benutzer = typeof benutzer.$inferSelect;
|
||||
export type Sitzung = typeof sitzung.$inferSelect;
|
||||
export type Ausbildung = typeof ausbildung.$inferSelect;
|
||||
@@ -131,6 +181,18 @@ export type HandoutGelesen = typeof handoutGelesen.$inferSelect;
|
||||
export type Wochenplanung = typeof wochenplanung.$inferSelect;
|
||||
export type Karte = typeof karte.$inferSelect;
|
||||
export type KartenVerlauf = typeof kartenVerlauf.$inferSelect;
|
||||
export type AufgabeStatus = typeof aufgabeStatus.$inferSelect;
|
||||
export type Anhang = typeof anhang.$inferSelect;
|
||||
|
||||
/** Wird von der Schema-Abgleichprüfung im Test verwendet. */
|
||||
export const alleTabellen = { benutzer, sitzung, ausbildung, handoutGelesen, wochenplanung, karte, kartenVerlauf };
|
||||
export const alleTabellen = {
|
||||
benutzer,
|
||||
sitzung,
|
||||
ausbildung,
|
||||
handoutGelesen,
|
||||
wochenplanung,
|
||||
karte,
|
||||
kartenVerlauf,
|
||||
aufgabeStatus,
|
||||
anhang,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user