From c6c027c8e0ffd52265b10441477b37b0ce7d1750 Mon Sep 17 00:00:00 2001 From: PlayerNguyen Date: Wed, 8 Jul 2026 15:11:38 +0700 Subject: [PATCH 1/2] feat: split AGENTS.md into docs/ and add PR template --- .github/pull_request_template.md | 58 +++++++++++++++ AGENTS.md | 119 ++++--------------------------- docs/api.md | 8 +++ docs/building.md | 14 ++++ docs/development.md | 24 +++++++ docs/getting-started.md | 22 ++++++ docs/infrastructure.md | 16 +++++ docs/path-aliases.md | 8 +++ docs/testing.md | 16 +++++ docs/ui.md | 7 ++ 10 files changed, 188 insertions(+), 104 deletions(-) create mode 100644 .github/pull_request_template.md create mode 100644 docs/api.md create mode 100644 docs/building.md create mode 100644 docs/development.md create mode 100644 docs/getting-started.md create mode 100644 docs/infrastructure.md create mode 100644 docs/path-aliases.md create mode 100644 docs/testing.md create mode 100644 docs/ui.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..ecd976e --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,58 @@ +## Summary + + + +## Type + + + +- [ ] Feature +- [ ] Bug fix +- [ ] Refactor +- [ ] Infrastructure / CI +- [ ] Documentation +- [ ] Other: ___ + +## Scope + + + +- [ ] `dashbore-api` (`apps/api/`) +- [ ] `dashbore-ui` (`apps/ui/`) +- [ ] `dashbore-common` (`packages/common/`) +- [ ] Root / config + +## Changes + + + +- +- +- + +## Motivation + + + +## Testing + + + +- [ ] `bun run test:api` passes +- [ ] `bun run test:ui` passes +- [ ] Manual testing (describe below) + +## Checklist + + + +- [ ] No `console.log` left in production code +- [ ] No secrets or keys committed +- [ ] Path aliases used correctly (`@/`, `@common/`) +- [ ] New code has tests (if applicable) +- [ ] API changes update OpenAPI spec (if applicable) +- [ ] UI changes work with Mantine + Tailwind v4 (if applicable) + +## Screenshots / Logs + + diff --git a/AGENTS.md b/AGENTS.md index 34c4f78..71889c9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,106 +1,17 @@ # Dashbore — AGENTS.md -## Runtime & package manager - -- **Bun** everywhere (v1.2.9+). Do not use npm/pnpm/yarn. -- Root `package.json` uses **Bun workspaces** (`"workspaces": ["apps/*", "packages/*"]`). - -## Monorepo structure - -| package | path | stack | -|---|---|---| -| `dashbore-api` | `apps/api/` | Hono + Prisma (MySQL) + JWT + Redis | -| `dashbore-ui` | `apps/ui/` | React 19 + Vite + TanStack Router + Mantine UI + Tailwind v4 + Zustand + TanStack Query | -| `dashbore-common` | `packages/common/` | Shared Zod schemas, re-exported through `@common/index` | - -## Installation - -```sh -bun install # single root install — workspaces handle the rest -``` - -`bun install` auto-runs `postinstall` scripts per workspace (prisma generate, etc). No special ordering needed. - -## Development - -### Infrastructure (required) -```sh -docker compose up -d # MySQL :3306, Redis :6379, Adminer :8080 -``` - -### Dev servers -```sh -bun run dev # concurrently runs dev-api + dev-ui -bun run dev:api # runs `prisma migrate dev` then starts Hono with --watch (:3000) -bun run dev:ui # Vite dev server (default :5173) -``` - -API `.env` (copy `apps/api/.env.example`): -- `DATABASE_URL=mysql://dashbore:dashbore@localhost:3306/dashbore` -- `JWT_SECRET`, `JWT_EXPIRATION_TIME`, `REDIS_URL` - -UI `.env` (copy `apps/ui/.env.example`): -- `VITE_API_URL=http://localhost:3000` - -### Testing - -```sh -bun run test # runs all tests with coverage (root) -bun run test:api # API only — runs migrate → seed → bun test -bun run test:ui # UI only — bun test -``` - -**API test quirks:** -- Test script: `cross-env NODE_ENV=test bun run migrate && bun run seed && bun test --preload ./tests/preload.ts` -- Requires MySQL + Redis running (`docker compose up -d`) -- Uses `apps/api/.env.test` (connects to `dashbore_test` database) -- Preload (`tests/preload.ts`) bootstraps permissions then logs in test user `dashbore@test.com` / `dashbore` -- Coverage threshold: 60% (`bunfig.toml` in both root and api) -- Test files go in `apps/api/tests/`, they import from `@/` (api) and `@common/` - -### Build - -```sh -bun run build # concurrently builds api + ui -bun run build:api # bun build → dist/index.js (bun target) -bun run build:ui # vite build -``` - -Or target a single workspace: -```sh -bun run --filter=dashbore-api dev -bun run --filter=dashbore-ui test -``` - -## Path aliases - -| alias | api (`tsconfig.json`) | ui (`vite.config.js` + `tsconfig.json`) | -|---|---|---| -| `@/` | `src/` | `./src/*` | -| `@common/` | `../../packages/common/src/*` | same | -| `@generated/prisma/` | `generated/prisma/*` | — | -| `@prisma/generated/` | — | `../api/generated/prisma/*` | - -## UI framework quirks - -- **TanStack Router** — route tree is **auto-generated** by `@tanstack/router-plugin/vite` into `src/routeTree.gen.ts`. Never edit this file; instead edit route files in `src/routes/`. Routes use file-based naming convention. -- **Mantine** — PostCSS config (`postcss.config.cjs`) requires `postcss-preset-mantine` + `postcss-simple-vars` for CSS variable breakpoints. -- **Tailwind CSS v4** — configured via `@tailwindcss/vite` plugin (no `tailwind.config.js` needed in v4). -- **TanStack Query** — global defaults set in `App.tsx` (no refetch on mount/focus/reconnect, `staleTime: Infinity`, `retry: false`). Do not add conflicting overrides without checking. -- Auth token stored in `localStorage` key `"token"` (JSON string). Interceptor in `src/api/axios.ts` attaches `Authorization: Bearer` header. - -## API framework quirks - -- Uses `hono/factory` with `createFactory()` typed factory pattern. -- OpenAPI spec auto-generated via `hono-openapi` builder pattern (`createOpenApiPathBuilder()`). -- Swagger UI at `GET /swagger`, OpenAPI spec at `GET /openapi`. -- Auth middleware has two modes: `useLightAuth()` (JWT verify only) and `useStrictAuth(permissions?)` (fetches user from DB, checks permissions). -- Permissions loaded on startup via `PermissionService.bootstrap()` (upserts any missing into DB). -- Redis caching used via `RedisCache.getOrSetCacheItem`. - -## Infrastructure (CI / docker-compose) - -- CI workflow (`.github/workflows/bun-test.yml`) mirrors local test flow: MySQL + Redis services → `bun install` → `bun run migrate` → `bun run seed` → `bun run test`. -- `docker-compose.yml` also includes Adminer (`:8080`) for DB inspection. -- MySQL init SQL: `.config/mysql/init.sql`. -- Data volumes: `.data/redis-data`, `.data/mysql` (both in `.gitignore`). +> Detailed project documentation lives in `docs/`. Read the relevant file +> before making changes to a workspace. + +## Quick reference + +| Topic | File | +|---|---| +| Getting started | `docs/getting-started.md` | +| Development | `docs/development.md` | +| Testing | `docs/testing.md` | +| Building | `docs/building.md` | +| Path aliases | `docs/path-aliases.md` | +| UI quirks | `docs/ui.md` | +| API quirks | `docs/api.md` | +| Infrastructure | `docs/infrastructure.md` | diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..d3dc3b9 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,8 @@ +# API Framework Quirks + +- Uses `hono/factory` with `createFactory()` typed factory pattern. +- OpenAPI spec auto-generated via `hono-openapi` builder pattern (`createOpenApiPathBuilder()`). +- Swagger UI at `GET /swagger`, OpenAPI spec at `GET /openapi`. +- Auth middleware has two modes: `useLightAuth()` (JWT verify only) and `useStrictAuth(permissions?)` (fetches user from DB, checks permissions). +- Permissions loaded on startup via `PermissionService.bootstrap()` (upserts any missing into DB). +- Redis caching used via `RedisCache.getOrSetCacheItem`. diff --git a/docs/building.md b/docs/building.md new file mode 100644 index 0000000..dc29d37 --- /dev/null +++ b/docs/building.md @@ -0,0 +1,14 @@ +# Building + +```sh +bun run build # concurrently builds api + ui +bun run build:api # bun build → dist/index.js (bun target) +bun run build:ui # vite build +``` + +Or target a single workspace: + +```sh +bun run --filter=dashbore-api dev +bun run --filter=dashbore-ui test +``` diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..27e12c7 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,24 @@ +# Development + +## Infrastructure (required) + +```sh +docker compose up -d # MySQL :3306, Redis :6379, Adminer :8080 +``` + +## Dev servers + +```sh +bun run dev # concurrently runs dev-api + dev-ui +bun run dev:api # runs `prisma migrate dev` then starts Hono with --watch (:3000) +bun run dev:ui # Vite dev server (default :5173) +``` + +## Environment variables + +API `.env` (copy `apps/api/.env.example`): +- `DATABASE_URL=mysql://dashbore:dashbore@localhost:3306/dashbore` +- `JWT_SECRET`, `JWT_EXPIRATION_TIME`, `REDIS_URL` + +UI `.env` (copy `apps/ui/.env.example`): +- `VITE_API_URL=http://localhost:3000` diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..a1f46f4 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,22 @@ +# Getting Started + +## Runtime & package manager + +- **Bun** everywhere (v1.2.9+). Do not use npm/pnpm/yarn. +- Root `package.json` uses **Bun workspaces** (`"workspaces": ["apps/*", "packages/*"]`). + +## Monorepo structure + +| package | path | stack | +|---|---|---| +| `dashbore-api` | `apps/api/` | Hono + Prisma (MySQL) + JWT + Redis | +| `dashbore-ui` | `apps/ui/` | React 19 + Vite + TanStack Router + Mantine UI + Tailwind v4 + Zustand + TanStack Query | +| `dashbore-common` | `packages/common/` | Shared Zod schemas, re-exported through `@common/index` | + +## Installation + +```sh +bun install # single root install — workspaces handle the rest +``` + +`bun install` auto-runs `postinstall` scripts per workspace (prisma generate, etc). No special ordering needed. diff --git a/docs/infrastructure.md b/docs/infrastructure.md new file mode 100644 index 0000000..cfb1131 --- /dev/null +++ b/docs/infrastructure.md @@ -0,0 +1,16 @@ +# Infrastructure + +## CI + +CI workflow (`.github/workflows/bun-test.yml`) mirrors local test flow: MySQL + Redis services → `bun install` → `bun run migrate` → `bun run seed` → `bun run test`. + +## Docker Compose + +`docker-compose.yml` includes: +- MySQL (`:3306`) +- Redis (`:6379`) +- Adminer (`:8080`) for DB inspection + +MySQL init SQL: `.config/mysql/init.sql`. + +Data volumes: `.data/redis-data`, `.data/mysql` (both in `.gitignore`). diff --git a/docs/path-aliases.md b/docs/path-aliases.md new file mode 100644 index 0000000..c242cbd --- /dev/null +++ b/docs/path-aliases.md @@ -0,0 +1,8 @@ +# Path Aliases + +| alias | api (`tsconfig.json`) | ui (`vite.config.js` + `tsconfig.json`) | +|---|---|---| +| `@/` | `src/` | `./src/*` | +| `@common/` | `../../packages/common/src/*` | same | +| `@generated/prisma/` | `generated/prisma/*` | — | +| `@prisma/generated/` | — | `../api/generated/prisma/*` | diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..95d54d3 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,16 @@ +# Testing + +```sh +bun run test # runs all tests with coverage (root) +bun run test:api # API only — runs migrate → seed → bun test +bun run test:ui # UI only — bun test +``` + +## API test quirks + +- Test script: `cross-env NODE_ENV=test bun run migrate && bun run seed && bun test --preload ./tests/preload.ts` +- Requires MySQL + Redis running (`docker compose up -d`) +- Uses `apps/api/.env.test` (connects to `dashbore_test` database) +- Preload (`tests/preload.ts`) bootstraps permissions then logs in test user `dashbore@test.com` / `dashbore` +- Coverage threshold: 60% (`bunfig.toml` in both root and api) +- Test files go in `apps/api/tests/`, they import from `@/` (api) and `@common/` diff --git a/docs/ui.md b/docs/ui.md new file mode 100644 index 0000000..9a183d8 --- /dev/null +++ b/docs/ui.md @@ -0,0 +1,7 @@ +# UI Framework Quirks + +- **TanStack Router** — route tree is **auto-generated** by `@tanstack/router-plugin/vite` into `src/routeTree.gen.ts`. Never edit this file; instead edit route files in `src/routes/`. Routes use file-based naming convention. +- **Mantine** — PostCSS config (`postcss.config.cjs`) requires `postcss-preset-mantine` + `postcss-simple-vars` for CSS variable breakpoints. +- **Tailwind CSS v4** — configured via `@tailwindcss/vite` plugin (no `tailwind.config.js` needed in v4). +- **TanStack Query** — global defaults set in `App.tsx` (no refetch on mount/focus/reconnect, `staleTime: Infinity`, `retry: false`). Do not add conflicting overrides without checking. +- Auth token stored in `localStorage` key `"token"` (JSON string). Interceptor in `src/api/axios.ts` attaches `Authorization: Bearer` header. From cbcd678af480bf5ca127c41e5df7557050407dbc Mon Sep 17 00:00:00 2001 From: PlayerNguyen Date: Wed, 8 Jul 2026 15:32:50 +0700 Subject: [PATCH 2/2] feat: add GitHub issue templates and update PR template --- .github/ISSUE_TEMPLATE/bug-report.yml | 82 ++++++ .github/ISSUE_TEMPLATE/config.yml | 8 + .github/ISSUE_TEMPLATE/feature-request.yml | 67 +++++ .github/ISSUE_TEMPLATE/infrastructure.yml | 56 ++++ .github/pull_request_template.md | 25 +- .../15-16-mysql-to-postgresql-migration.md | 255 ++++++++++++++++++ .opencode/skills/propose-plan/SKILL.md | 143 ++++++++++ opencode.jsonc | 37 +++ 8 files changed, 661 insertions(+), 12 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/ISSUE_TEMPLATE/infrastructure.yml create mode 100644 .opencode/plans/08-07-2026/15-16-mysql-to-postgresql-migration.md create mode 100644 .opencode/skills/propose-plan/SKILL.md create mode 100644 opencode.jsonc diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..2019548 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,82 @@ +name: Bug Report +description: Report a bug or unexpected behavior +labels: ["bug", "triage"] +body: + - type: markdown + attributes: + value: | + Thanks for reporting a bug! Please fill out the sections below. + + - type: textarea + id: description + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Steps to reproduce + description: Steps to reproduce the behavior. + placeholder: | + 1. Go to '...' + 2. Click on '...' + 3. See error + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected behavior + description: What you expected to happen. + validations: + required: true + + - type: dropdown + id: area + attributes: + label: Area affected + description: Which workspace is impacted? + options: + - API (`apps/api/`) + - UI (`apps/ui/`) + - Shared packages (`packages/*`) + - Infrastructure / CI + - Other + validations: + required: true + + - type: textarea + id: environment + attributes: + label: Environment + description: | + - OS: [e.g., macOS 14, Ubuntu 22.04] + - Bun version: [e.g., 1.1.0] + - Node version: [if applicable] + value: | + - OS: + - Bun: + - Node: + validations: + required: false + + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Paste any relevant logs, error messages, or stack traces. + render: shell + validations: + required: false + + - type: textarea + id: screenshots + attributes: + label: Screenshots + description: If applicable, add screenshots to help explain the problem. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..1fd03c7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Development Setup Help + url: https://github.com/nhng/dashbore/blob/master/docs/getting-started.md + about: Read the getting started guide before opening a setup issue + - name: Documentation + url: https://github.com/nhng/dashbore/tree/master/docs + about: Browse project documentation diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 0000000..239e1ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,67 @@ +name: Feature Request +description: Suggest a new feature or enhancement +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + Describe the feature you'd like to see added. + + - type: textarea + id: problem + attributes: + label: Problem statement + description: What problem does this feature solve? Is it related to a frustration? + placeholder: "I'm always frustrated when..." + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: Describe the solution you'd like. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Any alternative solutions or workarounds you've considered. + validations: + required: false + + - type: dropdown + id: area + attributes: + label: Area + description: Which part of the project does this relate to? + options: + - API (`apps/api/`) + - UI (`apps/ui/`) + - Shared packages (`packages/*`) + - Infrastructure / CI + - Other + validations: + required: true + + - type: dropdown + id: priority + attributes: + label: Priority + description: How important is this feature? + options: + - Nice to have + - Important + - Critical + validations: + required: false + + - type: textarea + id: additional + attributes: + label: Additional context + description: Any other context, mockups, or links. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/infrastructure.yml b/.github/ISSUE_TEMPLATE/infrastructure.yml new file mode 100644 index 0000000..c0164be --- /dev/null +++ b/.github/ISSUE_TEMPLATE/infrastructure.yml @@ -0,0 +1,56 @@ +name: Infrastructure Issue +description: Report CI/CD, Docker, database, or deployment issues +labels: ["infrastructure", "triage"] +body: + - type: markdown + attributes: + value: | + For issues related to CI, Docker, database, or deployment. + + - type: dropdown + id: category + attributes: + label: Category + description: What area of infrastructure is affected? + options: + - CI/CD (GitHub Actions) + - Docker / docker-compose + - Database / Prisma migrations + - Redis / caching + - Local development setup + - Other + validations: + required: true + + - type: textarea + id: description + attributes: + label: Describe the issue + description: What happened? What did you expect? + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Steps to reproduce + description: How can we reproduce this? + validations: + required: false + + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Paste logs, CI output, or error messages. + render: shell + validations: + required: false + + - type: textarea + id: config + attributes: + label: Relevant configuration + description: Paste any relevant config (docker-compose.yml, workflow YAML, .env snippets without secrets). + validations: + required: false diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ecd976e..53b3d19 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,10 +1,12 @@ ## Summary - + -## Type +## Related Issue + + - +## Type - [ ] Feature - [ ] Bug fix @@ -15,28 +17,29 @@ ## Scope - - - [ ] `dashbore-api` (`apps/api/`) - [ ] `dashbore-ui` (`apps/ui/`) - [ ] `dashbore-common` (`packages/common/`) +- [ ] `dashbore-database` (`packages/database/`) +- [ ] `dashbore-business` (`packages/business/`) +- [ ] `dashbore-cache` (`packages/cache/`) - [ ] Root / config ## Changes - - - - - ## Motivation - + -## Testing +## Dependencies + + - +## Testing - [ ] `bun run test:api` passes - [ ] `bun run test:ui` passes @@ -44,8 +47,6 @@ ## Checklist - - - [ ] No `console.log` left in production code - [ ] No secrets or keys committed - [ ] Path aliases used correctly (`@/`, `@common/`) diff --git a/.opencode/plans/08-07-2026/15-16-mysql-to-postgresql-migration.md b/.opencode/plans/08-07-2026/15-16-mysql-to-postgresql-migration.md new file mode 100644 index 0000000..57d4599 --- /dev/null +++ b/.opencode/plans/08-07-2026/15-16-mysql-to-postgresql-migration.md @@ -0,0 +1,255 @@ +# Plan: Migrate MySQL to PostgreSQL + +## Context + +The Dashbore application currently uses **MySQL 8** as its primary database. The goal is to migrate to **PostgreSQL** to leverage its advanced features (JSONB, native arrays, better full-text search, UUID type) and align with modern application standards. + +--- + +## Current State + +| Component | Current | +|---|---| +| Database | MySQL 8 | +| ORM | Prisma 7.0.0 | +| Driver Adapter | `@prisma/adapter-mariadb` | +| Connection | `mysql://dashbore:dashbore@localhost:3306/dashbore` | +| Docker Image | `mysql:8` | +| Admin UI | `adminer:latest` | + +--- + +## Target State + +| Component | Target | +|---|---| +| Database | PostgreSQL 17 | +| ORM | Prisma 7.0.0 | +| Driver Adapter | `@prisma/adapter-pg` (or native `pg` support) | +| Connection | `postgresql://dashbore:dashbore@localhost:5432/dashbore` | +| Docker Image | `postgres:17` | +| Admin UI | `adminer:latest` (or `dpage/pgadmin4`) | + +--- + +## Implementation Steps + +### Step 1: Docker Infrastructure + +**File: `docker-compose.yml`** + +Replace MySQL service with PostgreSQL: + +```yaml +db: + image: postgres:17 + container_name: dashbore-postgres + restart: unless-stopped + ports: + - "5432:5432" + environment: + POSTGRES_USER: dashbore + POSTGRES_PASSWORD: dashbore + POSTGRES_DB: dashbore + volumes: + - .config/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql + - .data/postgres:/var/lib/postgresql/data + networks: + - dashbore-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U dashbore -d dashbore"] + interval: 10s + timeout: 5s + retries: 5 +``` + +Remove or update the `adminer` service to work with PostgreSQL. + +--- + +### Step 2: PostgreSQL Init Script + +**New File: `.config/postgres/init.sql`** + +Replace the MySQL init script with PostgreSQL: + +```sql +-- Create test database +CREATE DATABASE dashbore_test; + +-- Grant all privileges +GRANT ALL PRIVILEGES ON DATABASE dashbore TO dashbore; +GRANT ALL PRIVILEGES ON DATABASE dashbore_test TO dashbore; +``` + +**Delete: `.config/mysql/init.sql`** + +--- + +### Step 3: Prisma Schema + +**File: `packages/database/prisma/schema.prisma`** + +Change the provider: + +```prisma +datasource db { + provider = "postgresql" // Changed from "mysql" + url = env("DATABASE_URL") +} +``` + +The rest of the schema remains the same—Prisma handles type mapping automatically. + +--- + +### Step 4: Package Dependencies + +**File: `packages/database/package.json`** + +```json +{ + "dependencies": { + "@prisma/adapter-pg": "^7.0.0", + "@prisma/client": "^7.0.0" + }, + "devDependencies": { + "prisma": "^7.0.0" + } +} +``` + +Remove `@prisma/adapter-mariadb` and add `@prisma/adapter-pg`. + +Run: `bun install` + +--- + +### Step 5: Prisma Client Configuration + +**File: `packages/database/src/index.ts`** + +Update the driver adapter import: + +```typescript +import { PrismaClient } from '../generated'; +import { PrismaPg } from '@prisma/adapter-pg'; + +const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL }); +const prisma = new PrismaClient({ adapter }); + +export default prisma; +``` + +--- + +### Step 6: Environment Variables + +**Files to update:** + +| File | Old | New | +|---|---|---| +| `apps/api/.env.example` | `mysql://dashbore:dashbore@localhost:3306/dashbore` | `postgresql://dashbore:dashbore@localhost:5432/dashbore` | +| `apps/api/.env.test` | `mysql://dashbore:dashbore@localhost:3306/dashbore_test` | `postgresql://dashbore:dashbore@localhost:5432/dashbore_test` | +| `packages/database/prisma.config.ts` | `mysql://dashbore:dashbore@localhost:3306/dashbore` | `postgresql://dashbore:dashbore@localhost:5432/dashbore` | + +--- + +### Step 7: CI/CD Pipeline + +**File: `.github/workflows/bun-test.yml`** + +Replace MySQL service with PostgreSQL: + +```yaml +services: + postgres: + image: postgres:17 + env: + POSTGRES_USER: dashbore + POSTGRES_PASSWORD: dashbore + POSTGRES_DB: dashbore_test + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 +``` + +Update the `DATABASE_URL` in the test environment to use PostgreSQL. + +--- + +### Step 8: Reset Migrations + +Since Prisma doesn't support cross-provider migrations: + +1. Delete `packages/database/prisma/migrations/` folder +2. Delete `packages/database/prisma/migration_lock.toml` +3. Run `bun run migrate` to create fresh PostgreSQL migrations +4. Verify migrations are generated with `provider = "postgresql"` in lock file + +--- + +### Step 9: Seed Script Verification + +**File: `packages/database/prisma/seed.ts`** + +The seed script uses Prisma Client API and should work as-is. Verify: +- `Bun.password.hashSync()` works (no DB dependency) +- All upsert operations complete successfully + +--- + +### Step 10: Testing + +1. Start PostgreSQL: `docker compose up db` +2. Run migrations: `bun run migrate` +3. Seed database: `bun run seed` +4. Run API tests: `bun run test --filter dashbore-api` +5. Verify all CRUD operations work +6. Check Adminer/PGAdmin connectivity + +--- + +## Key Differences: MySQL → PostgreSQL + +| Feature | MySQL | PostgreSQL | +|---|---|---| +| Boolean | `TINYINT(1)` | `BOOLEAN` | +| UUID | `CHAR(36)` | `UUID` | +| JSON | `JSON`/`JSONB` | `JSONB` | +| Arrays | Not supported | Native arrays | +| Full-text | `FULLTEXT` index | `tsvector` + `GIN` | +| Serial/Auto-increment | `AUTO_INCREMENT` | `SERIAL`/`GENERATED` | +| case-sensitive | Yes | Yes (by default) | + +--- + +## Rollback Plan + +If issues arise: +1. Revert `docker-compose.yml` to MySQL +2. Revert Prisma schema provider to `mysql` +3. Restore `@prisma/adapter-mariadb` dependency +4. Restore MySQL migrations from git history +5. Update environment variables back to MySQL + +--- + +## Verification Checklist + +- [ ] Docker PostgreSQL starts successfully +- [ ] PostgreSQL init script creates `dashbore_test` database +- [ ] Prisma schema compiles with `provider = "postgresql"` +- [ ] `bun run generate` produces Prisma Client +- [ ] `bun run migrate` creates tables in PostgreSQL +- [ ] `bun run seed` populates data successfully +- [ ] API starts and connects to PostgreSQL +- [ ] Authentication flow works (login, register) +- [ ] Permission system loads from DB +- [ ] Redis caching still works (independent of DB) +- [ ] All API tests pass +- [ ] CI pipeline runs with PostgreSQL diff --git a/.opencode/skills/propose-plan/SKILL.md b/.opencode/skills/propose-plan/SKILL.md new file mode 100644 index 0000000..c706a12 --- /dev/null +++ b/.opencode/skills/propose-plan/SKILL.md @@ -0,0 +1,143 @@ +--- +name: propose-plan +description: Propose a structured implementation plan for the user to review before execution +license: MIT +compatibility: opencode +metadata: + phase: planning + output: .opencode/plans/ +--- + +## Purpose + +Guide the user through a structured planning phase before implementing changes. This skill ensures clear understanding, proper analysis, and user approval before any code modifications. + +## When to Use + +- Before implementing new features +- Before refactoring existing code +- Before infrastructure changes (Docker, CI/CD, databases) +- Before any non-trivial modification that affects multiple files +- When user start prompting with keyword "propose". + +## Workflow + +### Phase 1: Understand the Request + +1. Read and understand the user's request +2. Identify the scope and impact of changes +3. Ask clarifying questions if the request is ambiguous + +### Phase 2: Explore the Codebase + +1. Use the `explore` agent or search tools to understand: + - Current implementation patterns + - Related files and dependencies + - Existing conventions and standards +2. Identify all files that need modification +3. Understand the impact on other components + +### Phase 3: Propose the Plan + +Present the plan in this structure: + +``` +## Context + + +## Current State + + +## Target State + + +## Implementation Steps + + +## Key Considerations + + +## Verification Checklist + +``` + +### Phase 4: Wait for Approval + +**Do not proceed with implementation until the user explicitly approves.** + +Present the plan and ask: +> "Does this plan look good? Should I proceed with implementation, or would you like any changes?" + +### Phase 5: Save the Plan (if requested) + +If the user approves and asks to save the plan: + +1. Get current timestamp: `date +"%d-%m-%Y-%H-%M"` +2. Create the plan file at `.opencode/plans/_.md` +3. Use the plan content from Phase 3 as the file content +4. Confirm the file was created + +## Rules + +1. **Never skip the planning phase** for non-trivial changes +2. **Always wait for user approval** before implementing +3. **Be specific** - reference exact file paths and line numbers +4. **Be honest** about risks and tradeoffs +5. **Ask questions** when the request is unclear +6. **Keep plans concise** but comprehensive +7. **Use existing patterns** - don't reinvent conventions + +## Project Config + +The root `opencode.jsonc` enables LSP for code intelligence: + +```jsonc +{ + "$schema": "https://opencode.ai/config.json", + "lsp": true +} +``` + +This provides type-aware suggestions and error checking during plan exploration. + +## Example Interaction + +``` +User: Migrate from MySQL to PostgreSQL + +Agent: I'll explore the codebase to understand the current database setup... + +[Explores codebase] + +Here's my migration plan: + +## Context +The app uses MySQL 8. We need to migrate to PostgreSQL. + +## Current State +- MySQL 8 in docker-compose.yml +- Prisma with @prisma/adapter-mariadb +- Connection: mysql://... + +## Target State +- PostgreSQL 17 in docker-compose.yml +- Prisma with @prisma/adapter-pg +- Connection: postgresql://... + +## Implementation Steps +1. Update docker-compose.yml (file:line) +2. Update prisma schema (file:line) +... + +## Verification Checklist +- [ ] PostgreSQL starts +- [ ] Migrations run +... + +Does this plan look good? Should I proceed, or would you like any changes? + +User: Looks good, save the plan + +Agent: [Creates .opencode/plans/08-07-2026-15-30_mysql-to-postgresql-migration.md] +Plan saved. Ready to implement when you are. +``` diff --git a/opencode.jsonc b/opencode.jsonc new file mode 100644 index 0000000..982820b --- /dev/null +++ b/opencode.jsonc @@ -0,0 +1,37 @@ +{ + "$schema": "https://opencode.ai/config.json", + + "lsp": true, + + "instructions": [ + "AGENTS.md", + "docs/**/*.md" + ], + + "watcher": { + "ignore": [ + "node_modules/**", + ".data/**", + ".prisma/**", + "@prisma/**", + "packages/database/generated/**", + "dist/**", + ".git/**", + "*.lock" + ] + }, + + "snapshot": true, + + "permission": { + "edit": "allow", + "write": "allow", + "bash": "ask" + }, + + "compaction": { + "auto": true, + "prune": false, + "reserved": 10000 + } +}