diff --git a/apps/api/src/lib/marketplace/ai-moderation.ts b/apps/api/src/lib/marketplace/ai-moderation.ts index 2326173..9f54f0a 100644 --- a/apps/api/src/lib/marketplace/ai-moderation.ts +++ b/apps/api/src/lib/marketplace/ai-moderation.ts @@ -15,7 +15,7 @@ * * Fail-open im Original: bei mana-llm-Ausfall wurde `flag` gesetzt, * damit ein menschlicher Reviewer es trotzdem sieht. Solange wir nur - * Cardecky-Decks publishen, ist der Stub `pass` ausreichend — Cardecky + * Wordeck-Decks publishen, ist der Stub `pass` ausreichend — Wordeck * ist eine kuratierte Identität. */ diff --git a/apps/api/src/routes/marketplace/fork.ts b/apps/api/src/routes/marketplace/fork.ts index d7bc20f..2d99359 100644 --- a/apps/api/src/routes/marketplace/fork.ts +++ b/apps/api/src/routes/marketplace/fork.ts @@ -146,11 +146,6 @@ export async function forkDeckForUser( function subIndexCountFor(type: string, fields: Record): number { if (type === 'cloze') return subIndexCountForCloze(fields.text ?? ''); - if (type === 'image-occlusion') { - // image-occlusion hat dynamische subIndexes via mask_regions — - // im Marketplace-Fork bisher nicht unterstützt. Default 1. - return 1; - } return subIndexCount(type); } diff --git a/apps/api/src/routes/marketplace/moderation.ts b/apps/api/src/routes/marketplace/moderation.ts index 1b2eedb..a6110d2 100644 --- a/apps/api/src/routes/marketplace/moderation.ts +++ b/apps/api/src/routes/marketplace/moderation.ts @@ -9,7 +9,7 @@ import { authorBlocks, authors, deckReports, publicDecks } from '../../db/schema /** * Moderation-Endpoints — App-Review-Pflicht für User-Generated-Content - * (App-Store-Guideline 5.1.1(v)). Aus Cardecky-Native erreichbar als + * (App-Store-Guideline 5.1.1(v)). Aus Wordeck-Native erreichbar als * „Melden" und „Author blockieren". * * - `POST /decks/:slug/report` — Meldung zu einem Deck. Idempotent diff --git a/apps/api/tests/cards.test.ts b/apps/api/tests/cards.test.ts index 0905bd1..4231589 100644 --- a/apps/api/tests/cards.test.ts +++ b/apps/api/tests/cards.test.ts @@ -75,7 +75,7 @@ describe('cardsRouter — Input-Validation', () => { expect(res.status).toBe(422); }); - it('POST mit image-occlusion ohne mask_regions ist 422', async () => { + it('POST mit image-occlusion ist 422 (CardType nicht mehr akzeptiert)', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/cards', { method: 'POST', @@ -83,49 +83,12 @@ describe('cardsRouter — Input-Validation', () => { body: JSON.stringify({ deck_id: 'd-1', type: 'image-occlusion', - fields: { image_ref: 'm1' }, + fields: { image_ref: 'm1', mask_regions: '[]' }, }), }); expect(res.status).toBe(422); }); - it('POST mit image-occlusion mit kaputtem mask_regions ist 422', async () => { - const { app } = buildApp(); - const res = await app.request('/api/v1/cards', { - method: 'POST', - headers: { 'X-User-Id': 'u-1', 'Content-Type': 'application/json' }, - body: JSON.stringify({ - deck_id: 'd-1', - type: 'image-occlusion', - fields: { image_ref: 'm1', mask_regions: 'not json' }, - }), - }); - expect(res.status).toBe(422); - const body = (await res.json()) as { issues: string[] }; - expect(body.issues[0]).toMatch(/mask_regions/); - }); - - it('POST mit gültiger image-occlusion erreicht Deck-Lookup (404 bei stub)', async () => { - const { app } = buildApp(); - const res = await app.request('/api/v1/cards', { - method: 'POST', - headers: { 'X-User-Id': 'u-1', 'Content-Type': 'application/json' }, - body: JSON.stringify({ - deck_id: 'd-1', - type: 'image-occlusion', - fields: { - image_ref: 'm1', - mask_regions: JSON.stringify([ - { id: 'r1', x: 0.1, y: 0.1, w: 0.1, h: 0.1 }, - ]), - }, - }), - }); - expect(res.status).toBe(404); - const body = (await res.json()) as { error: string }; - expect(body.error).toBe('deck_not_found'); - }); - it('POST mit cloze-Card ohne text-Feld ist 422', async () => { const { app } = buildApp(); const res = await app.request('/api/v1/cards', { diff --git a/apps/landing/astro.config.mjs b/apps/landing/astro.config.mjs deleted file mode 100644 index 5dee97a..0000000 --- a/apps/landing/astro.config.mjs +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'astro/config'; -import tailwind from '@astrojs/tailwind'; -import sitemap from '@astrojs/sitemap'; - -export default defineConfig({ - site: 'https://cardecky.mana.how', - integrations: [ - tailwind({ applyBaseStyles: false }), - sitemap(), - ], - output: 'static', -}); diff --git a/apps/landing/package.json b/apps/landing/package.json deleted file mode 100644 index 523bddd..0000000 --- a/apps/landing/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@cards/landing", - "type": "module", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "astro dev --port 4380", - "build": "astro build", - "preview": "astro preview --port 4380", - "astro": "astro" - }, - "dependencies": { - "astro": "^5.8.0" - }, - "devDependencies": { - "@astrojs/tailwind": "^6.0.2", - "@astrojs/sitemap": "^3.4.1", - "tailwindcss": "^3.4.17", - "typescript": "^5.8.3" - } -} diff --git a/apps/landing/public/favicon.svg b/apps/landing/public/favicon.svg deleted file mode 100644 index 94699ba..0000000 --- a/apps/landing/public/favicon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/apps/landing/src/components/BlogTeaser.astro b/apps/landing/src/components/BlogTeaser.astro deleted file mode 100644 index 730e0c1..0000000 --- a/apps/landing/src/components/BlogTeaser.astro +++ /dev/null @@ -1,75 +0,0 @@ ---- -const posts = [ - { - href: '/blog/quizlet-paywall', - tag: 'Migration', - title: 'Quizlet zieht die Paywall hoch — was jetzt?', - summary: - 'Fünf Millionen Nutzer:innen haben Quizlet in den letzten zwei Jahren verlassen. Was hinter der Bezahlschranke steckt und wie der Wechsel zu Cardecky in wenigen Minuten klappt.', - }, - { - href: '/blog/fsrs-algorithmus', - tag: 'Algorithmus', - title: 'Weniger lernen, mehr behalten: Was FSRS bedeutet', - summary: - 'FSRS reduziert die nötigen Wiederholungen um 20–30 % bei gleicher Retention. Wie der Algorithmus funktioniert — und warum er bei anderen Apps noch nicht der Standard ist.', - }, - { - href: '/blog/deine-daten', - tag: 'Datenschutz', - title: 'Deine Karten, deine Daten', - summary: - 'Lerndaten verraten mehr als die meisten ahnen. Was Cardecky damit macht — und was nicht — lässt sich im öffentlichen Quellcode nachprüfen.', - }, - { - href: '/blog/anki-zu-kompliziert', - tag: 'Vergleich', - title: 'Anki ist mächtig — und trotzdem schwer empfehlbar', - summary: - 'Anki ist technisch überlegen. Trotzdem hören die meisten Nutzer:innen auf — nicht wegen des Algorithmus, sondern wegen Interface und Lernkurve.', - }, - { - href: '/blog/gute-lernkarten', - tag: 'Lernen', - title: 'Wie man Lernkarten schreibt, die wirklich funktionieren', - summary: - 'Der beste Algorithmus nützt nichts, wenn die Karten schlecht gebaut sind. Fünf Prinzipien — mit Gegenbeispielen.', - }, -] as const; ---- - -
-
- -

Hintergrund & Methodik.

-

- Warum Spaced Repetition funktioniert, was die Konkurrenz falsch macht — und wie man - Karten baut, die das Gehirn tatsächlich behält. -

- - -
-
diff --git a/apps/landing/src/components/CTASection.astro b/apps/landing/src/components/CTASection.astro deleted file mode 100644 index 8aaa91c..0000000 --- a/apps/landing/src/components/CTASection.astro +++ /dev/null @@ -1,35 +0,0 @@ ---- -const APP_URL = 'https://cardecky.mana.how'; ---- -
-
-

- Bereit, das Lernen neu zu denken? -

-

- Cardecky ist kostenlos. Keine Kreditkarte, keine versteckten Kosten. -

- -
-
diff --git a/apps/landing/src/components/CardTypes.astro b/apps/landing/src/components/CardTypes.astro deleted file mode 100644 index 139dd85..0000000 --- a/apps/landing/src/components/CardTypes.astro +++ /dev/null @@ -1,74 +0,0 @@ ---- -const types = [ - { - name: 'Klassisch', - tag: 'basic', - icon: ``, - desc: 'Vorderseite und Rückseite. Der Klassiker — simpel, bewährt, effektiv für einfache Fakten.', - }, - { - name: 'Multiple Choice', - tag: 'multiple-choice', - icon: ``, - desc: 'Vier Antwortoptionen zur Auswahl. Fehlende Distractors generiert das System automatisch aus dem Deck.', - highlight: true, - }, - { - name: 'Lückentext', - tag: 'cloze', - icon: ``, - desc: 'Text mit {{c1::Lücken}} — jeder markierte Cluster wird als eigene Karte abgefragt.', - }, - { - name: 'Bild-Okklusion', - tag: 'image-occlusion', - icon: ``, - desc: 'Bereiche auf einem Bild ausblenden — ideal für Anatomie, Landkarten, Diagramme.', - }, - { - name: 'Tippen', - tag: 'typing', - icon: ``, - desc: 'Die Antwort eintippen statt nur aufzudecken. Fuzzy-Match verzeiht kleine Tippfehler.', - }, - { - name: 'Audio', - tag: 'audio-front', - icon: ``, - desc: 'Audioclip als Prompt — perfekt für Sprachlernen, Vokabeln und Aussprache-Training.', - }, -] as const; ---- -
-
- -

Sechs Formate, ein System.

-

- Nicht jedes Wissen lässt sich gleich lernen. Cardecky hat für jeden Lerninhalt den richtigen - Kartentyp — alle im gleichen Deck, alle mit FSRS-Scheduling. -

- -
- {types.map((type) => ( -
-
- -
-
-

{type.name}

- {type.tag} -
-

{type.desc}

-
- ))} -
-
-
diff --git a/apps/landing/src/components/Features.astro b/apps/landing/src/components/Features.astro deleted file mode 100644 index 9d2f405..0000000 --- a/apps/landing/src/components/Features.astro +++ /dev/null @@ -1,57 +0,0 @@ ---- -const features = [ - { - icon: ``, - title: 'Open Source', - body: 'Der gesamte Quellcode liegt offen auf Forgejo. Keine Blackbox, kein Vendor-Lock-in.', - }, - { - icon: ``, - title: 'Datensouveränität', - body: 'Deine Daten liegen auf mana-Infrastruktur in Europa. Kein Google, kein AWS, keine Datenhändler.', - }, - { - icon: ``, - title: 'FSRS-Algorithmus', - body: 'Free Spaced Repetition Scheduler — nachweislich effektiver als SM-2, das Herzstück von Anki.', - }, - { - icon: ``, - title: 'Anki-Import', - body: '.apkg-Dateien direkt importieren — Vorlagen werden automatisch auf Cardecky-Kartentypen gemappt.', - }, - { - icon: ``, - title: 'Öffentliche Bibliothek', - body: 'Kuratierte Decks zu Periodensystem, Geografie, Sprachen, Philosophie und mehr — ein Klick zum Start.', - }, - { - icon: ``, - title: 'Föderiert im mana-Ökosystem', - body: 'Cardecky teilt Identität und Credits mit den anderen mana-Apps — ein Login, eine Community.', - }, -] as const; ---- -
-
- -

Gebaut für ernsthaftes Lernen.

-

- Kein Feature-Bloat. Nur was du brauchst, um Wissen dauerhaft zu verankern. -

- -
- {features.map((f) => ( -
-
- -
-
-

{f.title}

-

{f.body}

-
-
- ))} -
-
-
diff --git a/apps/landing/src/components/Footer.astro b/apps/landing/src/components/Footer.astro deleted file mode 100644 index 0fc7d1e..0000000 --- a/apps/landing/src/components/Footer.astro +++ /dev/null @@ -1,51 +0,0 @@ ---- -const year = new Date().getFullYear(); ---- - diff --git a/apps/landing/src/components/Hero.astro b/apps/landing/src/components/Hero.astro deleted file mode 100644 index e754811..0000000 --- a/apps/landing/src/components/Hero.astro +++ /dev/null @@ -1,43 +0,0 @@ ---- -const APP_URL = 'https://cardecky.mana.how'; ---- -
- - - -
-
- - -

- Lernkarten, die
- tatsächlich wirken. -

- -

- Cardecky nutzt den FSRS-Algorithmus — den aktuellen Stand der Wissenschaft im Spaced - Repetition — um dir jede Karte genau dann zu zeigen, wenn du sie kurz vor dem Vergessen bist. - Keine Abos, keine Tracker, keine dark patterns. - Freie Software des mana e.V. -

- - - -

- Kein Account erforderlich für den ersten Blick · DSGVO-konform · Open Source -

-
-
-
diff --git a/apps/landing/src/components/HowItWorks.astro b/apps/landing/src/components/HowItWorks.astro deleted file mode 100644 index 0d601b1..0000000 --- a/apps/landing/src/components/HowItWorks.astro +++ /dev/null @@ -1,35 +0,0 @@ ---- -const steps = [ - { - n: '01', - title: 'Deck erstellen oder importieren', - body: 'Leg ein neues Deck an und füge Karten über das Web-Interface hinzu — oder importiere deine bestehenden Anki-Decks direkt als .apkg-Datei. Decks aus der Bibliothek mit einem Klick übernehmen.', - }, - { - n: '02', - title: 'Karten anlegen', - body: 'Wähle den passenden Kartentyp und füll die Felder aus. Für Multiple-Choice-Karten zieht das System automatisch passende Distractors aus dem restlichen Deck — du gibst nur die richtige Antwort vor.', - }, - { - n: '03', - title: 'Täglich kurz lernen', - body: 'Der FSRS-Algorithmus berechnet für jede Karte den optimalen Wiederholungszeitpunkt. Du bewertest dich selbst (Nochmal / Schwer / Gut / Leicht) — damit kalibriert sich das System auf deinen persönlichen Vergessenskurve.', - }, -] as const; ---- -
-
- -

In drei Schritten zur täglichen Praxis.

- -
- {steps.map((s) => ( -
- {s.n} -

{s.title}

-

{s.body}

-
- ))} -
-
-
diff --git a/apps/landing/src/components/ManaSection.astro b/apps/landing/src/components/ManaSection.astro deleted file mode 100644 index 67aba52..0000000 --- a/apps/landing/src/components/ManaSection.astro +++ /dev/null @@ -1,46 +0,0 @@ ---- ---- -
-
-
-
- -

- Software als Gemeingut. -

-

- Cardecky ist ein Projekt des mana e.V. — einem Schweizer Verein, - der digitale Infrastruktur als Gemeingut begreift. Keine Investoren, keine Werbung, - kein Daten-Harvesting. Finanziert durch freiwillige Mitgliedsbeiträge. -

-

- 80 % der Einnahmen fließen direkt in den Betrieb der Apps. 10 % in Langlebigkeit - und Nachhaltigkeit. 10 % in den Vereinsbetrieb. Transparenz ist kein Marketing — - wir veröffentlichen jeden Quartal einen Transparenzbericht. -

- -
- -
- {[ - { label: 'Open Source', desc: 'Quellcode liegt offen auf git.mana.how' }, - { label: 'Kein Tracking', desc: 'Keine Werbung, keine externen Dienste' }, - { label: 'Europa', desc: 'Daten auf Infrastruktur in Europa' }, - { label: 'Transparent', desc: 'Quartalsbericht zu Finanzen & Betrieb' }, - ].map((item) => ( -
-

{item.label}

-

{item.desc}

-
- ))} -
-
-
-
diff --git a/apps/landing/src/components/Nav.astro b/apps/landing/src/components/Nav.astro deleted file mode 100644 index cc4b747..0000000 --- a/apps/landing/src/components/Nav.astro +++ /dev/null @@ -1,24 +0,0 @@ ---- -const APP_URL = 'https://cardecky.mana.how'; ---- -
- -
diff --git a/apps/landing/src/layouts/Layout.astro b/apps/landing/src/layouts/Layout.astro deleted file mode 100644 index b3f4a8c..0000000 --- a/apps/landing/src/layouts/Layout.astro +++ /dev/null @@ -1,37 +0,0 @@ ---- -interface Props { - title: string; - description: string; - ogImage?: string; -} -const { title, description, ogImage = '/og.png' } = Astro.props; -const canonical = new URL(Astro.url.pathname, Astro.site); ---- - - - - - - - - - {title} - - - - - - - - - - - - - - - - - - - diff --git a/apps/landing/src/pages/blog/anki-zu-kompliziert.astro b/apps/landing/src/pages/blog/anki-zu-kompliziert.astro deleted file mode 100644 index 26e3fef..0000000 --- a/apps/landing/src/pages/blog/anki-zu-kompliziert.astro +++ /dev/null @@ -1,321 +0,0 @@ ---- -import Layout from '../../layouts/Layout.astro'; -import Nav from '../../components/Nav.astro'; -import Footer from '../../components/Footer.astro'; -import '../../styles/base.css'; - -const APP_URL = 'https://cardecky.mana.how'; -const ANKI_IMPORT_URL = 'https://cardecky.mana.how/import'; - -const title = 'Anki ist mächtig — und trotzdem schwer empfehlbar | Cardecky'; -const description = - 'Anki ist der Goldstandard für Spaced Repetition. Aber die Lernkurve ist brutal, das' + - ' Interface stammt aus 2006, und einen Freund damit anzufangen ist fast unmöglich. Was' + - ' Cardecky anders macht.'; ---- - - -