From cb0f17da15fbbcac4ffa086b8a286fe9852d775f Mon Sep 17 00:00:00 2001 From: bipproduction Date: Sun, 8 Feb 2026 13:53:27 +0800 Subject: [PATCH] docs: finalize README.md and GEMINI.md with full feature set --- GEMINI.md | 12 ++++- README.md | 91 +++++++++++++++++++++++++++++---- src/.well-known/assetlinks.json | 12 +++++ src/index.html | 11 ++++ src/index.ts | 37 ++++++++++++-- src/manifest.json | 17 ++++++ src/sw.js | 25 +++++++++ src/vite.ts | 2 +- 8 files changed, 193 insertions(+), 14 deletions(-) create mode 100644 src/.well-known/assetlinks.json create mode 100644 src/manifest.json create mode 100644 src/sw.js diff --git a/GEMINI.md b/GEMINI.md index 179cac8..eb59fc9 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -7,6 +7,7 @@ This project is **makuro-base-template**, a high-performance, full-stack React d * **Runtime**: [Bun](https://bun.sh/) * **Architecture**: "Single Port" (default: 3000). [ElysiaJS](https://elysiajs.com/) serves as the main HTTP server, integrating [Vite](https://vitejs.dev/) in **middleware mode** during development to provide HMR and React Dev Inspector support. * **API Design**: **Contract-First (OpenAPI)**. The frontend uses `openapi-fetch` with types generated from the backend's OpenAPI schema, ensuring a decoupled but type-safe connection. +* **Mobile Readiness**: **PWA (Progressive Web App)** & **TWA (Trusted Web Activity)**. Built-in support for offline caching and Android app packaging. * **Frontend**: React 19 with [TanStack React Router](https://tanstack.com/router/latest) for type-safe, file-based routing. * **UI Framework**: [Mantine UI](https://mantine.dev/) for a comprehensive component library and hooks. * **Authentication**: [Better Auth](https://www.better-auth.com/) integrated with Elysia. @@ -54,6 +55,12 @@ The project uses two main categories for testing, consolidated in the `__tests__ * **Sync**: Run `bun run gen:api` to export the OpenAPI `schema.json` and generate TypeScript types in `generated/api.ts`. * **Frontend Usage**: Use the `apiClient` from `@/utils/api-client`, which uses `openapi-fetch` for type-safe requests. +### Mobile & PWA +* **Manifest**: Metadata is located in `src/manifest.json`. +* **Service Worker**: Offline logic is in `src/sw.js`. It uses a "Cache First" strategy. +* **TWA Verification**: The Android ownership file is at `src/.well-known/assetlinks.json`. +* **Server Logic**: Elysia is configured to remove `Vary: *` headers for these static assets to ensure Cache Storage API compatibility. + ### Backend/API * **Prefix**: All backend API routes are prefixed with `/api`. * **Documentation**: Swagger/OpenAPI documentation is available at `/api/docs` in development. @@ -71,8 +78,11 @@ The project uses two main categories for testing, consolidated in the `__tests__ * `src/api/`: Elysia route modules and schema definitions. * `src/routes/`: Frontend route definitions and layouts. * `src/utils/`: Shared utilities (Auth, DB, Env, API Client). +* `src/sw.js`: PWA Service Worker. +* `src/manifest.json`: PWA Manifest. +* `src/.well-known/`: TWA verification assets. * `scripts/`: Automation scripts (e.g., `generate-schema.ts`). * `generated/`: Auto-generated artifacts (OpenAPI schema and types). * `__tests__/`: Centralized testing directory (`api/` and `e2e/`). * `prisma/`: Database schema and migrations. -* `dist/`: Production build output. +* `dist/`: Production build output. \ No newline at end of file diff --git a/README.md b/README.md index aea3fa8..10392c8 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,94 @@ -# makuro-base-template +# Makuro Base Template ๐Ÿš€ -To install dependencies: +[![Bun](https://img.shields.io/badge/Bun-%23000000.svg?style=for-the-badge&logo=bun&logoColor=white)](https://bun.sh/) +[![React](https://img.shields.io/badge/react-%2320232a.svg?style=for-the-badge&logo=react&logoColor=%2361DAFB)](https://react.dev/) +[![Mantine](https://img.shields.io/badge/Mantine-blue?style=for-the-badge&logo=mantine&logoColor=white)](https://mantine.dev/) +[![Biome](https://img.shields.io/badge/Biome-60a5fa?style=for-the-badge&logo=biome&logoColor=white)](https://biomejs.dev/) +**Makuro Base Template** is a high-performance, full-stack React development template leveraging the **Bun** runtime. It offers a unique "Single Port" architecture, combining a Bun/Elysia backend with a React frontend for an incredibly smooth developer experience. + +## โœจ Key Features + +- **โšก Single Port Architecture**: Backend (Elysia) and Frontend (Vite Middleware) run on the same port (3000). No CORS issues, no proxy complexity. +- **๐Ÿ“œ Contract-First API**: Strictly typed API using OpenAPI. Frontend types are automatically synced from backend schemas. +- **โš›๏ธ React 19 + TanStack Router**: The latest React features with type-safe, file-based routing. +- **๐ŸŽจ Mantine UI**: A comprehensive library of 100+ components and hooks, pre-configured with a modern dark theme. +- **๐Ÿ“ฑ PWA & TWA Support**: Ready for mobile with Service Workers, Web Manifest, and Android Trusted Web Activity verification. +- **๐Ÿ” React Dev Inspector**: `Alt/Option + Click` any element in your browser to jump directly to its source code in VS Code. +- **๐Ÿงช Modern Testing**: Fast unit/integration tests with Bun's native runner and E2E testing with Playwright. + +## ๐Ÿ›  Tech Stack + +| Layer | Technology | +| :--- | :--- | +| **Runtime** | [Bun](https://bun.sh/) (Fast all-in-one JS runtime) | +| **Backend** | [ElysiaJS](https://elysiajs.com/) (Fast, type-safe web framework) | +| **Frontend** | [React 19](https://react.dev/) (UI Library) | +| **Routing** | [TanStack React Router](https://tanstack.com/router/latest) (Type-safe routing) | +| **UI Framework** | [Mantine UI](https://mantine.dev/) (Component library) | +| **Auth** | [Better Auth](https://www.better-auth.com/) (Complete auth solution) | +| **Database** | [Prisma ORM](https://www.prisma.io/) (Database toolkit) | +| **Testing** | [Bun Test](https://bun.sh/docs/cli/test) & [Playwright](https://playwright.dev/) | + +## ๐Ÿ“ Project Structure + +```text +โ”œโ”€โ”€ __tests__/ # Consolidated test suite (API & E2E) +โ”œโ”€โ”€ generated/ # Auto-generated API types and Prisma client +โ”œโ”€โ”€ prisma/ # Database schema and migrations +โ”œโ”€โ”€ scripts/ # Internal automation scripts +โ””โ”€โ”€ src/ + โ”œโ”€โ”€ api/ # Elysia backend route modules + โ”œโ”€โ”€ middleware/ # Backend & Frontend middlewares + โ”œโ”€โ”€ routes/ # TanStack file-based frontend routes + โ”œโ”€โ”€ store/ # Global state (Valtio) + โ”œโ”€โ”€ utils/ # Shared utilities (DB, Env, API Client) + โ”œโ”€โ”€ frontend.tsx # React client entry point + โ””โ”€โ”€ index.ts # Unified server entry point +``` + +## ๐Ÿš€ Getting Started + +### 1. Prerequisites +Install [Bun](https://bun.sh/) if you haven't already. + +### 2. Installation ```bash bun install ``` -To start a development server: - +### 3. Setup Environment ```bash -bun dev +cp .env.example .env +# Fill in your DATABASE_URL and BETTER_AUTH_SECRET ``` -To run for production: - +### 4. Database Initialization ```bash -bun start +bun x prisma migrate dev ``` -This project was created using `bun init` in bun v1.3.6. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime. +### 5. Start Development +```bash +bun run dev +``` +- **App**: `http://localhost:3000` +- **API Docs**: `http://localhost:3000/api/docs` (Swagger) + +## ๐Ÿงช Testing Commands + +- **Unit/Integration (API)**: `bun run test` +- **End-to-End (Browser)**: `bun run test:e2e` +- **Visual Dashboard**: `bun run test:ui` + +## ๐Ÿ“ Development Guidelines + +- **API Workflow**: + 1. Define schema in `src/api/*.ts`. + 2. Run `bun run gen:api` (or just start `dev` mode). + 3. Use `apiClient` in the frontend with full type safety. +- **Styling**: Prefer Mantine components and Style Props. +- **Code Quality**: Code is automatically formatted on save if you have the Biome extension. Manual: `bun run check`. + +--- +Created with โค๏ธ by [Malik Kurosaki](https://github.com/malikkurosaki) \ No newline at end of file diff --git a/src/.well-known/assetlinks.json b/src/.well-known/assetlinks.json new file mode 100644 index 0000000..0826ec7 --- /dev/null +++ b/src/.well-known/assetlinks.json @@ -0,0 +1,12 @@ +[ + { + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "com.example.makuro", + "sha256_cert_fingerprints": [ + "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00" + ] + } + } +] diff --git a/src/index.html b/src/index.html index 5099837..45b4507 100644 --- a/src/index.html +++ b/src/index.html @@ -5,10 +5,21 @@ + + Bun + React
+ diff --git a/src/index.ts b/src/index.ts index 344c617..373e283 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,13 @@ if (!isProduction) { const { createVite } = await import("./vite"); const vite = await createVite(); + // Serve PWA/TWA assets in dev + app.get("/manifest.json", () => Bun.file("src/manifest.json")); + app.get("/sw.js", () => Bun.file("src/sw.js")); + app.get("/.well-known/assetlinks.json", () => + Bun.file("src/.well-known/assetlinks.json"), + ); + app.post("/__open-in-editor", ({ body }) => { const { relativePath, lineNumber, columnNumber } = body as { relativePath: string; @@ -42,7 +49,10 @@ if (!isProduction) { (!pathname.includes(".") && !pathname.startsWith("/@") && !pathname.startsWith("/inspector") && - !pathname.startsWith("/__open-stack-frame-in-editor")) + !pathname.startsWith("/__open-stack-frame-in-editor") && + !pathname.startsWith("/manifest.json") && + !pathname.startsWith("/sw.js") && + !pathname.startsWith("/.well-known/")) ) { try { const htmlPath = path.resolve("src/index.html"); @@ -134,6 +144,18 @@ if (!isProduction) { pathname === "/" ? "index.html" : pathname, ); + // 1.1 Special handling for PWA/TWA assets that might not be in dist (since we use custom bun build) + if ( + pathname === "/manifest.json" || + pathname === "/sw.js" || + pathname === "/.well-known/assetlinks.json" + ) { + const srcPath = path.join("src", pathname); + if (fs.existsSync(srcPath)) { + filePath = srcPath; + } + } + // 2. If not found and looks like an asset (has extension), try root of dist if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) { if (pathname.includes(".") && !pathname.endsWith("/")) { @@ -146,13 +168,22 @@ if (!isProduction) { } if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { - return new Response(Bun.file(filePath)); + const file = Bun.file(filePath); + return new Response(file, { + headers: { + "Vary": "Accept-Encoding", + } + }); } // 3. SPA Fallback: Serve index.html const indexHtml = path.join("dist", "index.html"); if (fs.existsSync(indexHtml)) { - return new Response(Bun.file(indexHtml)); + return new Response(Bun.file(indexHtml), { + headers: { + "Vary": "Accept-Encoding", + } + }); } return new Response("Not Found", { status: 404 }); diff --git a/src/manifest.json b/src/manifest.json new file mode 100644 index 0000000..6878560 --- /dev/null +++ b/src/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "Makuro Base Template", + "short_name": "Makuro", + "description": "A high-performance full-stack React template", + "start_url": "/", + "display": "standalone", + "background_color": "#1a1a1a", + "theme_color": "#f3d5a3", + "icons": [ + { + "src": "/logo.svg", + "sizes": "any", + "type": "image/svg+xml", + "purpose": "any maskable" + } + ] +} diff --git a/src/sw.js b/src/sw.js new file mode 100644 index 0000000..650da59 --- /dev/null +++ b/src/sw.js @@ -0,0 +1,25 @@ +const CACHE_NAME = 'makuro-v1'; +const ASSETS = [ + '/', + '/index.html', + '/logo.svg' +]; + +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => { + console.log('SW: Pre-caching assets'); + return cache.addAll(ASSETS).catch(err => { + console.error('SW: Pre-cache failed (likely due to Vary header or missing file):', err); + }); + }) + ); +}); + +self.addEventListener('fetch', (event) => { + event.respondWith( + caches.match(event.request).then((response) => { + return response || fetch(event.request); + }) + ); +}); diff --git a/src/vite.ts b/src/vite.ts index 2eb74b3..b5d54f5 100644 --- a/src/vite.ts +++ b/src/vite.ts @@ -34,7 +34,7 @@ export async function createVite() { }, appType: "custom", optimizeDeps: { - include: ["react", "react-dom", "@mantine/core"], + include: ["react", "react-dom", "@mantine/core", "manifest.json", "sw.js"], }, }); }