Skip to content

Shashank3736/quaslation

Repository files navigation

Quaslation

Version

Evidence-based technical overview and setup guide for the Quaslation web application.

Table of Contents

Project description

Quaslation is a Next.js App Router application for publishing high-quality fan translations of Asian web novels. It provides a reader UX with native commenting, RSS feed, SEO utilities, an admin surface for managing novels and chapters with moderation tools, and CLIs to fetch, translate, and import content into PostgreSQL via Drizzle ORM.

Key features and where they live

Architecture overview

  • Platform and frameworks
    • Next.js 16 App Router with React 19.2 and TypeScript
    • Styling: Tailwind CSS with typography plugin and animations
    • UI primitives: Radix UI and components under src/components/ui
  • Persistence and ORM
  • Authentication and authorization
    • Clerk for auth with server/client components initialized in RootLayout()
    • Role model via enum Role ADMIN/SUBSCRIBER/MEMBER in schema.ts
    • Helper for role retrieval getUserRole()
  • API layer
    • REST API routes under src/app/api for comments and user management
    • Role-based access control with Clerk integration
    • Batch fetching and enrichment of user data from Clerk
  • Caching and content delivery
    • Next ISR and tag-based invalidation on RSS route via unstable_cache in GET()
    • Client router cache reuse tuned via experimental.staleTimes in next.config.mjs
  • Community features
    • Native comment system with moderation capabilities
    • Discord webhooks for contact/support: actions.ts
  • Analytics and monetization

Architecture diagram

flowchart LR
  Browser -->|HTTP| NextApp[Next App Router]
  NextApp -->|Auth| Clerk[Clerk]
  NextApp -->|ORM| Drizzle[Drizzle ORM]
  Drizzle -->|SQL| Postgres[PostgreSQL]
  NextApp -->|Analytics| VercelAnalytics[Vercel Analytics]
  NextApp -->|GA| GoogleAnalytics[Google Analytics]
  NextApp -->|Webhook| Discord[Discord Webhook]
  Tools[CLI Tools] -->|Import| Postgres
  Tools -->|HTTP| Gradio[Gradio API]
  Tools -->|API| Gemini[Gemini API]
Loading

Data model

Primary entities defined in schema.ts:

  • User: clerkId (PK), role (enum: ADMIN/SUBSCRIBER/MEMBER)
  • RichText: text, html, markdown
  • Novel: slug, title, thumbnail, timestamps, richTextId (unique)
  • Volume: number, title, novelId, timestamps
  • Chapter: premium, slug, novelId, volumeId, serial, number, title, timestamps, richTextId
  • Comment: id, content, novelId, userId, isHidden, isEdited, timestamps Notable constraints:
  • Unique Novel.slug/title; unique Novel.richTextId link
  • Volume unique on novelId+number
  • Chapter unique on novelId+serial and volumeId+number; index on premium
  • Comment indexed on novelId, userId, and createdAt; cascading deletes on novel/user removal

Entity relationships

erDiagram
  NOVEL ||--o{ VOLUME : has
  NOVEL ||--o{ CHAPTER : has
  NOVEL ||--o{ COMMENT : receives
  VOLUME ||--o{ CHAPTER : groups
  RICH_TEXT ||--|| NOVEL : describes
  RICH_TEXT ||--|| CHAPTER : content
  USER ||--o{ COMMENT : writes
Loading

Database structure and connections

erDiagram
  USER {
    TEXT clerkId PK
    ENUM role
  }

  RICH_TEXT {
    INT id PK
    TEXT text
    TEXT html
    TEXT markdown
  }

  NOVEL {
    INT id PK
    TEXT slug
    TEXT title
    TEXT thumbnail
    TIMESTAMP createdAt
    TIMESTAMP publishedAt
    TIMESTAMP updatedAt
    INT richTextId FK
  }

  VOLUME {
    INT id PK
    DOUBLE number
    TEXT title
    TIMESTAMP createdAt
    TIMESTAMP publishedAt
    TIMESTAMP updatedAt
    INT novelId FK
  }

  CHAPTER {
    INT id PK
    BOOLEAN premium
    TEXT slug
    INT novelId FK
    INT volumeId FK
    INT serial
    DOUBLE number
    TEXT title
    TIMESTAMP createdAt
    TIMESTAMP publishedAt
    TIMESTAMP updatedAt
    INT richTextId FK
  }

  COMMENT {
    INT id PK
    TEXT content
    INT novelId FK
    TEXT userId FK
    BOOLEAN isHidden
    BOOLEAN isEdited
    TIMESTAMP createdAt
    TIMESTAMP updatedAt
  }

  NOVEL ||--o{ VOLUME : contains
  NOVEL ||--o{ CHAPTER : contains
  NOVEL ||--o{ COMMENT : receives
  VOLUME ||--o{ CHAPTER : groups
  RICH_TEXT ||--|| NOVEL : describes
  RICH_TEXT ||--|| CHAPTER : content
  USER ||--o{ COMMENT : writes
Loading

Setup and local development

Prerequisites

Install and configure

  • Install dependencies
    • npm install
  • Create environment file
    • cp .env.example .env.local
  • Populate required env vars (see Environment variables), especially DIRECT_URL for drizzle-kit

Database schema and migrations

  • Drizzle config points to schema.ts and outputs to src/lib/db in drizzle.config.ts
  • Commands
    • Generate SQL:
      npm run db:generate
    • Apply migrations:
      npm run db:migrate
    • Push schema:
      npm run db:push
    • Studio:
      npm run db:studio

Run locally

  • Development server:
    npm run dev
  • Lint:
    npm run lint
  • Type check:
    npx tsc --noEmit

Build and start

  • Production build:
    npm run build
  • Start server:
    npm run start

Production and deployment

  • Runtime DB driver is @vercel/postgres via index.ts, indicating Vercel-friendly deployment. @vercel/analytics is enabled.
  • Alternative Postgres providers can be used if environment variables are provided. Migration docs cover Supabase → Neon: scripts/migrate/README.md
  • Images remotePatterns whitelist Supabase storage in next.config.mjs

CLI tools

Gemini translation toolkit

  • Guide: scripts/gemini/README.md
  • Translate with concurrency and resume:
    • npx tsx scripts/gemini/main.ts --volume all --concurrency 2
  • Upload translated markdown to DB:
    • npx tsx scripts/gemini/upload.ts --novel-id 17 --verbose

Kakuyomu fetcher and Gradio translator

  • Guide: scripts/translation/README.md
  • Fetch chapters:
    • npx tsx scripts/translation/kakuyomu-fetch.ts --url https://kakuyomu.jp/works/16818093090655323692 --out scripts/output/translation
  • Translate with resume/skip:
    • npx tsx scripts/translation/translate.ts --baseDir scripts/output/translation --work 16818093090655323692 --concurrency 2

Environment variables

Defined in .env.example and referenced in code

  • Authentication
    • CLERK_SECRET_KEY
    • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
    • NEXT_PUBLIC_CLERK_SIGN_IN_URL (default /auth/sign-in)
    • NEXT_PUBLIC_CLERK_SIGN_UP_URL (default /auth/sign-up)
  • Analytics and ads
  • Community and support
  • Database and tooling
  • Caching (optional)
    • KV_REST_API_URL - Vercel KV for role caching
    • KV_REST_API_TOKEN - Vercel KV authentication token
  • AI integrations

Testing, linting, and type checking

  • Tests: No test suites detected in package.json. TODO: add unit/integration tests and coverage.
  • Linting: ESLint via Next config; run
    npm run lint
  • Type checking: run
    npx tsc --noEmit

CI/CD

  • Build verification in GitHub Actions: .github/workflows/nextjs-build.yml uses Node 20, restores Next cache, and runs build.
  • No coverage or deploy workflows present in repo; badges intentionally omitted.

Observability and analytics

  • Vercel Analytics initialized in RootLayout()
  • Optional Google Analytics via NEXT_PUBLIC_GOOGLE_ANALYTICS_ID

Security

  • Authentication via Clerk; app shell wraps with ClerkProvider
  • Role model for users via enum Role in schema.ts
  • Premium content gating via Chapter.premium and indexed access patterns in schema.ts and queries like getReleases()
  • Webhooks to Discord for support requests actions.ts
  • Secrets via environment variables; ensure .env.local is not committed

Performance and scalability

Roadmap and known limitations

  • Add automated tests and coverage reporting. TODO
  • Add deploy workflow (Vercel or other) and optional status badges. TODO
  • Clarify runtime DB configuration for local dev when not using @vercel/postgres. TODO
  • Containerization and dev database bootstrap scripts. TODO
  • Observability beyond analytics: structured logging and tracing. TODO

Contributing

License and contact

  • Treat as source-available; do not redistribute without permission.
  • Maintainer contact: shreyashr267@gmail.com

Differentiators at a glance

  • End-to-end pipeline for novel translation: fetch, translate (Gemini or Gradio), and upload to DB, documented under scripts
  • Clean, type-safe data access with Drizzle and explicit schema schema.ts
  • Production-aware caching and SEO with RSS + sitemap GET(), sitemap()
  • Native comment system with admin moderation and Clerk integration

About

Simple website to share web novels

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •