Belajar mengenali penyakit daun jagung dengan alur digital yang rapi.
Scaffold ini menyiapkan fondasi aplikasi ZeaVis Edu untuk antarmuka edukasi, API, dan integrasi model machine learning berikutnya.
# Fullstack Monorepo Scaffold Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Build the Bun + Moon fullstack TypeScript scaffold for ZeaVis Edu beside the existing `Machine_Learning/` pipeline. **Architecture:** Add a root Bun workspace managed by Moon with three projects: `apps/web`, `apps/api`, and `packages/shared`. The frontend is a React/Vite app with landing and dashboard routes; the backend is an Elysia API with health/status endpoints and Drizzle/PostgreSQL configuration that does not require a live database for startup. **Tech Stack:** Bun, Moon, TypeScript, React, Vite, React Router, TanStack Query, Zustand, Tailwind CSS, shadcn/ui-style components, Elysia, Drizzle ORM, PostgreSQL. --- ## File Structure Create these root files: - `package.json`: Bun workspaces, package manager marker, root scripts delegating to Moon. - `bunfig.toml`: Bun install/runtime defaults. - `tsconfig.base.json`: shared strict TypeScript compiler options. - `.env.example`: app ports and `DATABASE_URL` documentation. - `.gitignore`: ignore JS/TS dependency, build, env, and Moon cache outputs while preserving existing ML files. - `.moon/workspace.yml`: Moon workspace configuration. - `.moon/toolchain.yml`: Bun/Node toolchain configuration. Create `packages/shared`: - `packages/shared/package.json`: package metadata and export paths. - `packages/shared/tsconfig.json`: TypeScript config extending root base. - `packages/shared/src/index.ts`: shared exports. - `packages/shared/src/app-status.ts`: shared app status response type and factory. Create `apps/api`: - `apps/api/package.json`: API dependencies and scripts. - `apps/api/tsconfig.json`: API TypeScript config. - `apps/api/drizzle.config.ts`: Drizzle Kit config using `DATABASE_URL`. - `apps/api/src/index.ts`: Elysia server entry. - `apps/api/src/config/env.ts`: env helpers for port and database URL. - `apps/api/src/routes/health.ts`: `/health` route. - `apps/api/src/routes/status.ts`: `/api/v1/status` route. - `apps/api/src/db/schema.ts`: minimal schema placeholder. - `apps/api/src/db/client.ts`: Drizzle client factory that is not used at server boot. Create `apps/web`: - `apps/web/package.json`: frontend dependencies and scripts. - `apps/web/tsconfig.json`: app TypeScript config. - `apps/web/tsconfig.node.json`: Vite config TypeScript config. - `apps/web/vite.config.ts`: Vite React config. - `apps/web/index.html`: Vite HTML entry. - `apps/web/postcss.config.js`: PostCSS config for Tailwind. - `apps/web/tailwind.config.ts`: Tailwind content/theme config. - `apps/web/src/main.tsx`: React root render. - `apps/web/src/app.tsx`: providers and router wiring. - `apps/web/src/index.css`: Tailwind layers and theme variables. - `apps/web/src/lib/utils.ts`: `cn` utility. - `apps/web/src/store/ui-store.ts`: small Zustand UI store. - `apps/web/src/components/ui/button.tsx`: shadcn-style button. - `apps/web/src/components/ui/card.tsx`: shadcn-style card. - `apps/web/src/pages/landing-page.tsx`: landing route. - `apps/web/src/pages/dashboard-page.tsx`: placeholder dashboard route. Create Moon project files: - `apps/web/moon.yml`: web tasks. - `apps/api/moon.yml`: api tasks. - `packages/shared/moon.yml`: shared tasks. --- ### Task 1: Root Workspace and Moon Configuration **Files:** - Create: `package.json` - Create: `bunfig.toml` - Create: `tsconfig.base.json` - Create: `.env.example` - Create: `.gitignore` - Create: `.moon/workspace.yml` - Create: `.moon/toolchain.yml` - [ ] **Step 1: Create root package configuration** Create `package.json`: ```json { "name": "zeavis-edu", "private": true, "packageManager": "bun@1.1.42", "workspaces": [ "apps/*", "packages/*" ], "scripts": { "dev": "moon run :dev", "build": "moon run :build", "typecheck": "moon run :typecheck" }, "devDependencies": { "@moonrepo/cli": "^1.32.4", "typescript": "^5.6.3" } } ``` - [ ] **Step 2: Create Bun config** Create `bunfig.toml`: ```toml [install] exact = true ``` - [ ] **Step 3: Create shared TypeScript base config** Create `tsconfig.base.json`: ```json { "compilerOptions": { "target": "ES2022", "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"], "allowJs": false, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "ESNext", "moduleResolution": "Bundler", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", "baseUrl": ".", "paths": { "@zeavis/shared": ["packages/shared/src/index.ts"], "@zeavis/shared/*": ["packages/shared/src/*"] } } } ``` - [ ] **Step 4: Create environment example** Create `.env.example`: ```dotenv WEB_PORT=5173 API_PORT=3000 DATABASE_URL=postgres://postgres:postgres@localhost:5432/zeavis_edu ``` - [ ] **Step 5: Create root gitignore** Create `.gitignore`: ```gitignore node_modules/ .bun/ .moon/cache/ .env .env.* !.env.example dist/ build/ coverage/ *.tsbuildinfo .DS_Store ``` - [ ] **Step 6: Create Moon workspace config** Create `.moon/workspace.yml`: ```yaml projects: web: apps/web api: apps/api shared: packages/shared ``` - [ ] **Step 7: Create Moon toolchain config** Create `.moon/toolchain.yml`: ```yaml node: packageManager: bun ``` - [ ] **Step 8: Verify root config files are present** Run: `test -f package.json && test -f .moon/workspace.yml && test -f tsconfig.base.json` Expected: command exits with status 0 and no output. - [ ] **Step 9: Commit root workspace config** ```bash git add package.json bunfig.toml tsconfig.base.json .env.example .gitignore .moon/workspace.yml .moon/toolchain.yml git commit -m "Add Bun and Moon workspace configuration" ``` --- ### Task 2: Shared Package **Files:** - Create: `packages/shared/package.json` - Create: `packages/shared/tsconfig.json` - Create: `packages/shared/src/index.ts` - Create: `packages/shared/src/app-status.ts` - Create: `packages/shared/moon.yml` - [ ] **Step 1: Create shared package metadata** Create `packages/shared/package.json`: ```json { "name": "@zeavis/shared", "version": "0.1.0", "private": true, "type": "module", "exports": { ".": "./src/index.ts", "./app-status": "./src/app-status.ts" }, "scripts": { "typecheck": "tsc --project tsconfig.json" }, "devDependencies": { "typescript": "^5.6.3" } } ``` - [ ] **Step 2: Create shared TypeScript config** Create `packages/shared/tsconfig.json`: ```json { "extends": "../../tsconfig.base.json", "compilerOptions": { "lib": ["ES2022"], "types": [] }, "include": ["src"] } ``` - [ ] **Step 3: Create shared app status type** Create `packages/shared/src/app-status.ts`: ```ts export type AppStatus = { name: 'ZeaVis Edu'; status: 'ok'; version: string; }; export function createAppStatus(version = '0.1.0'): AppStatus { return { name: 'ZeaVis Edu', status: 'ok', version, }; } ``` - [ ] **Step 4: Create shared package export** Create `packages/shared/src/index.ts`: ```ts export type { AppStatus } from './app-status'; export { createAppStatus } from './app-status'; ``` - [ ] **Step 5: Create shared Moon tasks** Create `packages/shared/moon.yml`: ```yaml type: library language: typescript tasks: typecheck: command: bun run typecheck inputs: - src/**/* - tsconfig.json - package.json ``` - [ ] **Step 6: Run shared package typecheck after dependencies are installed** Run after Task 5 Step 1 has installed dependencies: `bun --cwd packages/shared run typecheck` Expected: TypeScript exits with status 0. - [ ] **Step 7: Commit shared package** ```bash git add packages/shared git commit -m "Add shared TypeScript package" ``` --- ### Task 3: Elysia API Scaffold **Files:** - Create: `apps/api/package.json` - Create: `apps/api/tsconfig.json` - Create: `apps/api/drizzle.config.ts` - Create: `apps/api/src/index.ts` - Create: `apps/api/src/config/env.ts` - Create: `apps/api/src/routes/health.ts` - Create: `apps/api/src/routes/status.ts` - Create: `apps/api/src/db/schema.ts` - Create: `apps/api/src/db/client.ts` - Create: `apps/api/moon.yml` - [ ] **Step 1: Create API package metadata** Create `apps/api/package.json`: ```json { "name": "@zeavis/api", "version": "0.1.0", "private": true, "type": "module", "scripts": { "dev": "bun --watch src/index.ts", "start": "bun src/index.ts", "typecheck": "tsc --project tsconfig.json", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate" }, "dependencies": { "@zeavis/shared": "workspace:*", "drizzle-orm": "^0.36.4", "elysia": "^1.1.25", "postgres": "^3.4.5" }, "devDependencies": { "drizzle-kit": "^0.27.1", "typescript": "^5.6.3" } } ``` - [ ] **Step 2: Create API TypeScript config** Create `apps/api/tsconfig.json`: ```json { "extends": "../../tsconfig.base.json", "compilerOptions": { "lib": ["ES2022"], "types": ["bun"], "noEmit": true }, "include": ["src", "drizzle.config.ts"] } ``` - [ ] **Step 3: Create API environment helper** Create `apps/api/src/config/env.ts`: ```ts export const env = { port: Number(Bun.env.API_PORT ?? 3000), databaseUrl: Bun.env.DATABASE_URL, }; ``` - [ ] **Step 4: Create health route** Create `apps/api/src/routes/health.ts`: ```ts import { Elysia } from 'elysia'; export const healthRoutes = new Elysia().get('/health', () => ({ status: 'ok' as const, })); ``` - [ ] **Step 5: Create status route using shared package** Create `apps/api/src/routes/status.ts`: ```ts import { createAppStatus } from '@zeavis/shared'; import { Elysia } from 'elysia'; export const statusRoutes = new Elysia({ prefix: '/api/v1' }).get('/status', () => createAppStatus(), ); ``` - [ ] **Step 6: Create Drizzle schema placeholder** Create `apps/api/src/db/schema.ts`: ```ts import { pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'; export const appEvents = pgTable('app_events', { id: uuid('id').primaryKey().defaultRandom(), name: varchar('name', { length: 120 }).notNull(), createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), }); ``` - [ ] **Step 7: Create Drizzle client factory** Create `apps/api/src/db/client.ts`: ```ts import { drizzle } from 'drizzle-orm/postgres-js'; import postgres from 'postgres'; import { env } from '../config/env'; import * as schema from './schema'; export function createDbClient() { if (!env.databaseUrl) { throw new Error('DATABASE_URL is required to create a database client'); } const client = postgres(env.databaseUrl); return drizzle(client, { schema }); } ``` - [ ] **Step 8: Create Drizzle config** Create `apps/api/drizzle.config.ts`: ```ts import { defineConfig } from 'drizzle-kit'; export default defineConfig({ schema: './src/db/schema.ts', out: './drizzle', dialect: 'postgresql', dbCredentials: { url: process.env.DATABASE_URL ?? 'postgres://postgres:postgres@localhost:5432/zeavis_edu', }, }); ``` - [ ] **Step 9: Create Elysia server entry** Create `apps/api/src/index.ts`: ```ts import { Elysia } from 'elysia'; import { env } from './config/env'; import { healthRoutes } from './routes/health'; import { statusRoutes } from './routes/status'; const app = new Elysia().use(healthRoutes).use(statusRoutes).listen(env.port); console.log(`ZeaVis Edu API running at http://${app.server?.hostname}:${app.server?.port}`); export type App = typeof app; ``` - [ ] **Step 10: Create API Moon tasks** Create `apps/api/moon.yml`: ```yaml type: application language: typescript tasks: dev: command: bun run dev local: true build: command: bun build src/index.ts --outdir dist --target bun inputs: - src/**/* - package.json - tsconfig.json - drizzle.config.ts outputs: - dist typecheck: command: bun run typecheck inputs: - src/**/* - package.json - tsconfig.json - drizzle.config.ts ``` - [ ] **Step 11: Commit API scaffold** ```bash git add apps/api git commit -m "Add Elysia API scaffold" ``` --- ### Task 4: React Web Scaffold **Files:** - Create: `apps/web/package.json` - Create: `apps/web/tsconfig.json` - Create: `apps/web/tsconfig.node.json` - Create: `apps/web/vite.config.ts` - Create: `apps/web/index.html` - Create: `apps/web/postcss.config.js` - Create: `apps/web/tailwind.config.ts` - Create: `apps/web/src/main.tsx` - Create: `apps/web/src/app.tsx` - Create: `apps/web/src/index.css` - Create: `apps/web/src/lib/utils.ts` - Create: `apps/web/src/store/ui-store.ts` - Create: `apps/web/src/components/ui/button.tsx` - Create: `apps/web/src/components/ui/card.tsx` - Create: `apps/web/src/pages/landing-page.tsx` - Create: `apps/web/src/pages/dashboard-page.tsx` - Create: `apps/web/moon.yml` - [ ] **Step 1: Create web package metadata** Create `apps/web/package.json`: ```json { "name": "@zeavis/web", "version": "0.1.0", "private": true, "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", "build": "tsc --project tsconfig.json && vite build", "preview": "vite preview --host 0.0.0.0", "typecheck": "tsc --project tsconfig.json" }, "dependencies": { "@tanstack/react-query": "^5.59.16", "@vitejs/plugin-react": "^4.3.3", "@zeavis/shared": "workspace:*", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.468.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.28.0", "tailwind-merge": "^2.5.4", "zustand": "^5.0.1" }, "devDependencies": { "autoprefixer": "^10.4.20", "postcss": "^8.4.49", "tailwindcss": "^3.4.15", "typescript": "^5.6.3", "vite": "^6.0.1" } } ``` - [ ] **Step 2: Create web TypeScript config** Create `apps/web/tsconfig.json`: ```json { "extends": "../../tsconfig.base.json", "compilerOptions": { "types": ["vite/client"], "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@zeavis/shared": ["../../packages/shared/src/index.ts"], "@zeavis/shared/*": ["../../packages/shared/src/*"] } }, "include": ["src"], "references": [{ "path": "./tsconfig.node.json" }] } ``` - [ ] **Step 3: Create Vite TypeScript config** Create `apps/web/tsconfig.node.json`: ```json { "extends": "../../tsconfig.base.json", "compilerOptions": { "composite": true, "module": "ESNext", "moduleResolution": "Bundler", "types": ["node"] }, "include": ["vite.config.ts", "tailwind.config.ts"] } ``` - [ ] **Step 4: Create Vite config** Create `apps/web/vite.config.ts`: ```ts import react from '@vitejs/plugin-react'; import path from 'node:path'; import { defineConfig } from 'vite'; export default defineConfig({ plugins: [react()], resolve: { alias: { '@': path.resolve(__dirname, './src'), }, }, }); ``` - [ ] **Step 5: Create Vite HTML entry** Create `apps/web/index.html`: ```html
Scaffold ini menyiapkan fondasi aplikasi ZeaVis Edu untuk antarmuka edukasi, API, dan integrasi model machine learning berikutnya.
Placeholder awal untuk fitur deteksi, riwayat analisis, dan edukasi.