Skip to content

Repository files navigation

application-face

The frontend for Nihongo Master — a minimal, text-first way to drill Japanese for the JLPT. A marketing/content site (landing, about, docs, blog, changelog, learn, contribute) sits in front of the game: a spaced-repetition Review (FSRS) plus four free-practice modes — Kana, Kanji, Vocabulary, and Listening.


Stack

Framework Next.js 16 (App Router, Turbopack, RSC)
Language TypeScript 5 — strict mode
Styling Tailwind CSS v4 (CSS @theme, no JS config) + PostCSS
State Zustand (persisted JLPT level)
Spaced repetition FSRS via ts-fsrs, stored in IndexedDB (dexie) — client-side, no account
Content MDX in /content (next-mdx-remote, gray-matter)
Fonts Self-hosted Helvetica Neue via next/font/local
Design Strict monochrome (grayscale + black/white), text-first
License MIT (code)

Quick start

git clone https://github.com/Nihongo-Master/Application-Face.git
cd application-face
npm install
npm run dev

The dev server runs at http://localhost:3000 with Turbopack.


Scripts

Command Description
npm run dev Development server (Turbopack) on localhost:3000
npm run build Production build → .next/
npm start Serve the production build (run build first)
npm run lint ESLint across the project
npm run data:download Download raw datasets into Data/raw/
npm run build:data Regenerate JLPT JSON in src/data/json/ and public/data/

Project structure

application-face/
│
├── content/                    # MDX content (read at build time, not bundled)
│   ├── blog/                    #   posts (frontmatter: title, date, tags, draft)
│   ├── changelog/               #   one file per release (version, date, title)
│   ├── docs/                    #   API reference: data/ · engine/ · api/
│   └── learn/                   #   guides & cheat sheets
│
├── public/                     # Static assets at /
│   ├── data/                    #   generated JLPT JSON (the open Data API)
│   ├── audio/  images/  fonts/
│
├── src/
│   ├── app/
│   │   ├── layout.tsx           # Root: <html>, fonts, metadata, StoreHydrator
│   │   ├── globals.css          # Tailwind v4 @theme + base styles
│   │   ├── sitemap.ts robots.ts # SEO routes
│   │   ├── not-found.tsx        # 404
│   │   ├── (site)/              # Marketing route group — SiteHeader/SiteFooter
│   │   │   ├── page.tsx          #   landing (/)
│   │   │   ├── about/ contribute/
│   │   │   ├── docs/             #   hub + [...slug] (+ layout with sidebar)
│   │   │   ├── learn/  blog/  changelog/
│   │   │   └── blog/rss.xml/     #   RSS feed route
│   │   └── (game)/              # Game route group — keeps GameShell chrome
│   │       ├── review/           #   spaced-repetition (FSRS) hub
│   │       ├── kana/ (+ play→/kana redirect)
│   │       └── kanji/ vocabulary/ listening/
│   │
│   ├── components/
│   │   ├── site/                # Marketing chrome + content UI (+ mdx/ renderer)
│   │   ├── game/                # Game-specific UI
│   │   ├── layout/GameShell.tsx # Shared game chrome
│   │   └── ui/                  # Primitives: Button, Input, LevelPicker
│   │
│   ├── data/                    # Pure data + typed loaders; srsItems (SRS units)
│   ├── engine/                  # Framework-agnostic logic (quiz, kanaSession, srs/FSRS)
│   ├── hooks/                   # React glue (useQuizSession, useKanaSession, useSrs)
│   ├── store/                   # Zustand (settingsStore — JLPT level)
│   └── lib/
│       ├── cn.ts site.ts date.ts
│       ├── srs/                 # IndexedDB (Dexie) store + JSON export/import
│       └── content/             # MDX content layer (blog, docs, learn, changelog)
│
├── docs/                        # improvements.md (plan), map.md, copy specs
├── next.config.ts               # Security headers + CSP, Turbopack root
└── tsconfig.json                # strict; @/* → src/*

The route groups (site) and (game) do not affect URLs — they only let the marketing pages and the game use different layouts/chrome. /, /kana, /kanji, /vocabulary, /listening are unchanged.

Layering

dataenginehookscomponents. The engine imports no React or DOM; components reach the engine only through hooks; data is the only place that reads the JSON datasets. See content/docs/engine for the contributor docs (also served at /docs/engine).


Content

Blog posts, changelog entries, docs, and learn guides are MDX files under content/. They're parsed with gray-matter and rendered server-side with next-mdx-remote/rsc — so nothing is fetched at runtime and the strict CSP is untouched. Add a post by dropping a .mdx file into content/blog/ (see content/blog/_template.mdx); files starting with _ and draft: true are excluded from listings, RSS, and the sitemap.


Spaced repetition (Review)

/review schedules practice with FSRS (via ts-fsrs). Card state lives in IndexedDB (Dexie) on the device — no account, works offline, no CSP change. Export backup / Import backup move progress between devices as JSON (last-write-wins). Layers: src/engine/srs.ts (scheduler), src/data/srsItems.ts (reviewable units), src/lib/srs/db.ts (store + backup), src/hooks/useSrs.ts (reactive counts). See /docs/engine/srs for the full reference.


Configuration

  • next.config.ts — security headers and a strict Content-Security-Policy (default-src 'self'). NEXT_PUBLIC_ASSET_HOST adds an allowed image origin (e.g. a Cloudflare R2/CDN domain) to img-src.
  • Tailwind v4 — there is no tailwind.config.ts. Theme tokens live in src/app/globals.css under @theme.
  • tsconfig.json — strict mode; @/* maps to src/*.
  • Fonts — self-hosted only. Do not add next/font/google (offline + CSP constraint); self-host or name an installed font.

Environment variables

Variable Required Description
NEXT_PUBLIC_SITE_URL Recommended Canonical origin for SEO, sitemap, and RSS (e.g. https://nihongo-master.app). Falls back to http://localhost:3000.
NEXT_PUBLIC_ASSET_HOST Optional Bare origin for externally hosted images (R2/CDN), added to the CSP img-src.

Deployment

Self-hosted (Coolify) behind Cloudflare; static images can be served from Cloudflare R2 via NEXT_PUBLIC_ASSET_HOST. The app is fully static/SSG today — no database is required at runtime (a REST API backed by Mongo/Redis is planned; see /docs/api/overview).

npm run build
npm start            # serves on PORT (default 3000)

Conventions

  • Server Components by default; add "use client" only at leaf nodes that need browser APIs or state.
  • Styling is Tailwind utilities; keep it monochrome (neutral scale + black/white).
  • Commits follow Conventional Commits (feat:, fix:, docs:, chore:, refactor:…).
  • File naming — PascalCase components, camelCase hooks/utils, lowercase Next.js special files.

License

Code is released under the MIT License © Nihongo Master. The bundled language data derives from third-party sources (KANJIDIC, JMdict, JLPT word lists) under their own terms — see /docs/data/overview.

About

A minimal, text-first way to drill Japanese for the JLPT. Spaced-repetition review (FSRS) plus free-practice modes for Kana, Kanji, Vocabulary, and Listening — no account needed, works offline.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages