georgeandClaude Opus 5 74054338f4 Possessive levels showed the stem where every other level shows the gender
On the possessive levels the second line read "unser- (our)" — the stem —
while articles, contractions and adjectives all put the noun and its gender
there. The gender was still available, but demoted into the third line as a
tail on the case hint, so the thing you actually need was the least visible
thing on screen.

The stem was telling you nothing either way: possessive answer options are
generated to share the question's stem, so all four already start with
unser-/ihr-/euer-. It was spending the most prominent hint slot on the one
fact the options could not hide.

Articles, contractions, possessives and adjectives now render the same
second line — noun, gender-coloured article, English gloss — under the same
`gender` toggle, so hiding it on one level hides it on all of them. The
duplicate gender tail is gone from the case line, and the possessive-only
hint and its toggle are removed.

Pronoun questions keep their own hint. They have no noun at all, and which
pronoun is meant is genuinely not recoverable from the sentence, so that is
the right hint for them rather than an inconsistency.

Wechsel im Kontext keeps its preposition hint for the same reason: the
answer there is a case, not a declined form, so the noun's gender is not
part of the question and the preposition's English gloss is what helps.

142 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Uza6mhTpAvSwMQuFc4Cz8
2026-10-02 07:04:51 +00:00
2026-07-05 12:48:27 +02:00
2026-07-05 12:48:27 +02:00

Deklinationstrainer

A daily-practice German declension trainer. Self-hosted so your progress actually saves.

Deploy to Coolify

One-time setup

  1. Push these files to a git repo (GitHub / Gitea / whatever Coolify is connected to).

  2. In Coolify, create a new Application:

    • Source: your git repo
    • Build pack: Nixpacks (auto-detects Vite) or Static
    • Build command: npm run build
    • Publish directory: dist
    • Port: not needed for static output (Coolify serves it directly)
  3. Add a domain (e.g. deklination.yourdomain.com). Coolify provisions HTTPS via Caddy/Traefik automatically.

  4. Deploy. Visit the URL on any device.

Local dev

npm install
npm run dev    # http://localhost:5173
npm run build  # outputs to ./dist

On iPhone

Open the URL in Safari, tap Share → Add to Home Screen. It opens fullscreen like a native app, and progress saves in localStorage across reboots, sessions, and app closes.

Storage

The app tries window.storage first (Claude artifact environment), then falls back to localStorage. When self-hosted, only localStorage runs, which iOS Safari persists reliably.

To wipe progress: open browser devtools → Application → Local Storage → delete the gd-v10 key. Or on iPhone: Settings → Safari → Advanced → Website Data → search your domain → delete.

Stripe checkout

Beug uses public Stripe Checkout or Payment Link URLs, supplied through environment variables. Do not put Stripe secret keys in this Vite app.

Payments are behind a launch-mode flag:

VITE_PAYMENTS_ENABLED=false

When VITE_PAYMENTS_ENABLED is absent or false, the app runs in Reddit/free mode: all lessons are usable, paid rows are not blurred, and the paywall/pricing screen is hidden. The Stripe URLs can stay configured in the environment so billing can be switched back on later with one env change.

To turn payments back on, set:

VITE_PAYMENTS_ENABLED=true

Create one product in Stripe, for example Beug Premium, with three prices:

  • Weekly subscription: $2.99 every week
  • Yearly subscription: $9.99 every year
  • Lifetime access: $19.99 one-time payment

Create a Payment Link or Checkout link for each price. Set the success redirect URL to:

https://beug.george1.dev/?checkout=success

Set the cancel URL to:

https://beug.george1.dev/

Then add these public URLs in the deployment environment:

VITE_STRIPE_YEARLY_URL=https://buy.stripe.com/...
VITE_STRIPE_LIFETIME_URL=https://buy.stripe.com/...
VITE_STRIPE_WEEKLY_URL=https://buy.stripe.com/...

The current v1 unlock is intentionally simple: after Stripe redirects back with ?checkout=success, Beug stores the unlock in this browser's localStorage. This avoids accounts for the tiny-app version, but it is a soft paywall. A stricter version needs a small backend, Stripe webhooks, and account or email-based entitlement lookup.

Future prompt to re-enable payments

Turn payments back on for Beug. Set VITE_PAYMENTS_ENABLED=true in Coolify, keep the three existing Stripe Payment Link env vars, redeploy the app, and verify that unpaid users see the soft paid lesson blur, that charts remain visible, and that tapping a paid lesson opens the pricing screen with Weekly, Yearly, and Lifetime plans.
S
Description
No description provided
Readme
4 MiB
Languages
JavaScript 99.7%
HTML 0.2%