feat(#1): Set up monorepo scaffold with pnpm workspaces + TurboRepo
Implements the foundational project structure including: - pnpm workspaces configuration - TurboRepo for build orchestration - NestJS 11.1.12 API (apps/api) - Next.js 16.1.6 web app (apps/web) - Shared packages (config, shared, ui) - TypeScript strict mode configuration - ESLint + Prettier setup - Vitest for unit testing (19 passing tests) Fixes #1 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
17
.env.example
Normal file
17
.env.example
Normal file
@@ -0,0 +1,17 @@
|
||||
# API Configuration
|
||||
API_PORT=3001
|
||||
API_HOST=0.0.0.0
|
||||
|
||||
# Web Configuration
|
||||
NEXT_PUBLIC_API_URL=http://localhost:3001
|
||||
|
||||
# Database (configured in later milestone)
|
||||
# DATABASE_URL=postgresql://user:password@localhost:5432/mosaic
|
||||
|
||||
# Authentication (configured in later milestone)
|
||||
# OIDC_ISSUER=https://auth.example.com
|
||||
# OIDC_CLIENT_ID=your-client-id
|
||||
# OIDC_CLIENT_SECRET=your-client-secret
|
||||
|
||||
# Development
|
||||
NODE_ENV=development
|
||||
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
.pnpm-store
|
||||
|
||||
# Build outputs
|
||||
dist
|
||||
.next
|
||||
.turbo
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# Testing
|
||||
coverage
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pnpm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Misc
|
||||
*.tsbuildinfo
|
||||
6
.prettierignore
Normal file
6
.prettierignore
Normal file
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
dist
|
||||
.next
|
||||
.turbo
|
||||
coverage
|
||||
pnpm-lock.yaml
|
||||
3
.prettierrc.js
Normal file
3
.prettierrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import config from "@mosaic/config/prettier";
|
||||
|
||||
export default config;
|
||||
313
CLAUDE.md
Normal file
313
CLAUDE.md
Normal file
@@ -0,0 +1,313 @@
|
||||
**Multi-tenant personal assistant platform with PostgreSQL backend, Authentik SSO, and MoltBot
|
||||
integration.**
|
||||
|
||||
## Project Overview
|
||||
|
||||
Mosaic Stack is a standalone platform that provides:
|
||||
- Multi-user workspaces with team sharing
|
||||
- Task, event, and project management
|
||||
- Gantt charts and Kanban boards
|
||||
- MoltBot integration via plugins (stock MoltBot + mosaic-plugin-*)
|
||||
- PDA-friendly design throughout
|
||||
|
||||
**Repository:** git.mosaicstack.dev/mosaic/stack
|
||||
**Versioning:** Start at 0.0.1, MVP = 0.1.0
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Layer | Technology |
|
||||
|-------|------------|
|
||||
| Frontend | Next.js 16 + React + TailwindCSS + Shadcn/ui |
|
||||
| Backend | NestJS + Prisma ORM |
|
||||
| Database | PostgreSQL 17 + pgvector |
|
||||
| Cache | Valkey (Redis-compatible) |
|
||||
| Auth | Authentik (OIDC) |
|
||||
| AI | Ollama (configurable: local or remote) |
|
||||
| Messaging | MoltBot (stock + Mosaic plugins) |
|
||||
| Real-time | WebSockets (Socket.io) |
|
||||
| Monorepo | pnpm workspaces + TurboRepo |
|
||||
| Testing | Vitest + Playwright |
|
||||
| Deployment | Docker + docker-compose |
|
||||
|
||||
## Repository Structure
|
||||
|
||||
mosaic-stack/
|
||||
├── apps/
|
||||
│ ├── api/ # mosaic-api (NestJS)
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── auth/ # Authentik OIDC
|
||||
│ │ │ ├── tasks/ # Task management
|
||||
│ │ │ ├── events/ # Calendar/events
|
||||
│ │ │ ├── projects/ # Project management
|
||||
│ │ │ ├── brain/ # MoltBot integration
|
||||
│ │ │ └── activity/ # Activity logging
|
||||
│ │ ├── prisma/
|
||||
│ │ │ └── schema.prisma
|
||||
│ │ └── Dockerfile
|
||||
│ └── web/ # mosaic-web (Next.js 16)
|
||||
│ ├── app/
|
||||
│ ├── components/
|
||||
│ └── Dockerfile
|
||||
├── packages/
|
||||
│ ├── shared/ # Shared types, utilities
|
||||
│ ├── ui/ # Shared UI components
|
||||
│ └── config/ # Shared configuration
|
||||
├── plugins/
|
||||
│ ├── mosaic-plugin-brain/ # MoltBot skill: API queries
|
||||
│ ├── mosaic-plugin-calendar/ # MoltBot skill: Calendar
|
||||
│ ├── mosaic-plugin-tasks/ # MoltBot skill: Tasks
|
||||
│ └── mosaic-plugin-gantt/ # MoltBot skill: Gantt
|
||||
├── docker/
|
||||
│ ├── docker-compose.yml # Turnkey deployment
|
||||
│ └── init-scripts/ # PostgreSQL init
|
||||
├── docs/
|
||||
│ ├── SETUP.md
|
||||
│ ├── CONFIGURATION.md
|
||||
│ └── DESIGN-PRINCIPLES.md
|
||||
├── .env.example
|
||||
├── turbo.json
|
||||
├── pnpm-workspace.yaml
|
||||
└── README.md
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Branch Strategy
|
||||
- `main` — stable releases only
|
||||
- `develop` — active development (default working branch)
|
||||
- `feature/*` — feature branches from develop
|
||||
- `fix/*` — bug fix branches
|
||||
|
||||
### Starting Work
|
||||
```bash
|
||||
git checkout develop
|
||||
git pull --rebase
|
||||
pnpm install
|
||||
|
||||
Running Locally
|
||||
|
||||
# Start all services (Docker)
|
||||
docker compose up -d
|
||||
|
||||
# Or run individually for development
|
||||
pnpm dev # All apps
|
||||
pnpm dev:api # API only
|
||||
pnpm dev:web # Web only
|
||||
|
||||
Testing
|
||||
|
||||
pnpm test # Run all tests
|
||||
pnpm test:api # API tests only
|
||||
pnpm test:web # Web tests only
|
||||
pnpm test:e2e # Playwright E2E
|
||||
|
||||
Building
|
||||
|
||||
pnpm build # Build all
|
||||
pnpm build:api # Build API
|
||||
pnpm build:web # Build Web
|
||||
|
||||
Design Principles (NON-NEGOTIABLE)
|
||||
|
||||
PDA-Friendly Language
|
||||
|
||||
NEVER use demanding language. This is critical.
|
||||
┌─────────────┬──────────────────────┐
|
||||
│ ❌ NEVER │ ✅ ALWAYS │
|
||||
├─────────────┼──────────────────────┤
|
||||
│ OVERDUE │ Target passed │
|
||||
├─────────────┼──────────────────────┤
|
||||
│ URGENT │ Approaching target │
|
||||
├─────────────┼──────────────────────┤
|
||||
│ MUST DO │ Scheduled for │
|
||||
├─────────────┼──────────────────────┤
|
||||
│ CRITICAL │ High priority │
|
||||
├─────────────┼──────────────────────┤
|
||||
│ YOU NEED TO │ Consider / Option to │
|
||||
├─────────────┼──────────────────────┤
|
||||
│ REQUIRED │ Recommended │
|
||||
└─────────────┴──────────────────────┘
|
||||
Visual Indicators
|
||||
|
||||
Use status indicators consistently:
|
||||
- 🟢 On track / Active
|
||||
- 🔵 Upcoming / Scheduled
|
||||
- ⏸️ Paused / On hold
|
||||
- 💤 Dormant / Inactive
|
||||
- ⚪ Not started
|
||||
|
||||
Display Principles
|
||||
|
||||
1. 10-second scannability — Key info visible immediately
|
||||
2. Visual chunking — Clear sections with headers
|
||||
3. Single-line items — Compact, scannable lists
|
||||
4. Date grouping — Today, Tomorrow, This Week headers
|
||||
5. Progressive disclosure — Details on click, not upfront
|
||||
6. Calm colors — No aggressive reds for status
|
||||
|
||||
Reference
|
||||
|
||||
See docs/DESIGN-PRINCIPLES.md for complete guidelines.
|
||||
For original patterns, see: jarvis-brain/docs/DESIGN-PRINCIPLES.md
|
||||
|
||||
API Conventions
|
||||
|
||||
Endpoints
|
||||
|
||||
GET /api/{resource} # List (with pagination, filters)
|
||||
GET /api/{resource}/:id # Get single
|
||||
POST /api/{resource} # Create
|
||||
PATCH /api/{resource}/:id # Update
|
||||
DELETE /api/{resource}/:id # Delete
|
||||
|
||||
Response Format
|
||||
|
||||
// Success
|
||||
{
|
||||
data: T | T[],
|
||||
meta?: { total, page, limit }
|
||||
}
|
||||
|
||||
// Error
|
||||
{
|
||||
error: {
|
||||
code: string,
|
||||
message: string,
|
||||
details?: any
|
||||
}
|
||||
}
|
||||
|
||||
Brain Query API
|
||||
|
||||
POST /api/brain/query
|
||||
{
|
||||
query: "what's on my calendar",
|
||||
context?: { view: "dashboard", workspace_id: "..." }
|
||||
}
|
||||
|
||||
Database Conventions
|
||||
|
||||
Multi-Tenant (RLS)
|
||||
|
||||
All workspace-scoped tables use Row-Level Security:
|
||||
- Always include workspace_id in queries
|
||||
- RLS policies enforce isolation
|
||||
- Set session context for current user
|
||||
|
||||
Prisma Commands
|
||||
|
||||
pnpm prisma:generate # Generate client
|
||||
pnpm prisma:migrate # Run migrations
|
||||
pnpm prisma:studio # Open Prisma Studio
|
||||
pnpm prisma:seed # Seed development data
|
||||
|
||||
MoltBot Plugin Development
|
||||
|
||||
Plugins live in plugins/mosaic-plugin-*/ and follow MoltBot skill format:
|
||||
|
||||
# plugins/mosaic-plugin-brain/SKILL.md
|
||||
---
|
||||
name: mosaic-plugin-brain
|
||||
description: Query Mosaic Stack for tasks, events, projects
|
||||
version: 0.0.1
|
||||
triggers:
|
||||
- "what's on my calendar"
|
||||
- "show my tasks"
|
||||
- "morning briefing"
|
||||
tools:
|
||||
- mosaic_api
|
||||
---
|
||||
|
||||
# Plugin instructions here...
|
||||
|
||||
Key principle: MoltBot remains stock. All customization via plugins only.
|
||||
|
||||
Environment Variables
|
||||
|
||||
See .env.example for all variables. Key ones:
|
||||
|
||||
# Database
|
||||
DATABASE_URL=postgresql://mosaic:password@localhost:5432/mosaic
|
||||
|
||||
# Auth
|
||||
AUTHENTIK_URL=https://auth.example.com
|
||||
AUTHENTIK_CLIENT_ID=mosaic-stack
|
||||
AUTHENTIK_CLIENT_SECRET=...
|
||||
|
||||
# Ollama
|
||||
OLLAMA_MODE=local|remote
|
||||
OLLAMA_ENDPOINT=http://localhost:11434
|
||||
|
||||
# MoltBot
|
||||
MOSAIC_API_TOKEN=...
|
||||
|
||||
Issue Tracking
|
||||
|
||||
Issues are tracked at: https://git.mosaicstack.dev/mosaic/stack/issues
|
||||
|
||||
Labels
|
||||
|
||||
- Priority: p0 (critical), p1 (high), p2 (medium), p3 (low)
|
||||
- Type: api, web, database, auth, plugin, ai, devops, docs, migration, security, testing,
|
||||
performance, setup
|
||||
|
||||
Milestones
|
||||
|
||||
- M1-Foundation (0.0.x)
|
||||
- M2-MultiTenant (0.0.x)
|
||||
- M3-Features (0.0.x)
|
||||
- M4-MoltBot (0.0.x)
|
||||
- M5-Migration (0.1.0 MVP)
|
||||
|
||||
Commit Format
|
||||
|
||||
<type>(#issue): Brief description
|
||||
|
||||
Detailed explanation if needed.
|
||||
|
||||
Fixes #123
|
||||
Types: feat, fix, docs, test, refactor, chore
|
||||
|
||||
Testing Requirements
|
||||
|
||||
- Minimum 85% coverage for new code
|
||||
- Write tests before implementation (TDD)
|
||||
- All tests must pass before PR merge
|
||||
|
||||
Docker Deployment
|
||||
|
||||
Turnkey (includes everything)
|
||||
|
||||
docker compose up -d
|
||||
|
||||
Customized (external services)
|
||||
|
||||
Create docker-compose.override.yml to:
|
||||
- Point to external PostgreSQL/Valkey/Ollama
|
||||
- Disable bundled services
|
||||
|
||||
See docs/DOCKER.md for details.
|
||||
|
||||
Key Documentation
|
||||
┌───────────────────────────┬───────────────────────┐
|
||||
│ Document │ Purpose │
|
||||
├───────────────────────────┼───────────────────────┤
|
||||
│ docs/SETUP.md │ Installation guide │
|
||||
├───────────────────────────┼───────────────────────┤
|
||||
│ docs/CONFIGURATION.md │ All config options │
|
||||
├───────────────────────────┼───────────────────────┤
|
||||
│ docs/DESIGN-PRINCIPLES.md │ PDA-friendly patterns │
|
||||
├───────────────────────────┼───────────────────────┤
|
||||
│ docs/DOCKER.md │ Docker deployment │
|
||||
├───────────────────────────┼───────────────────────┤
|
||||
│ docs/API.md │ API documentation │
|
||||
└───────────────────────────┴───────────────────────┘
|
||||
Related Repositories
|
||||
┌──────────────┬──────────────────────────────────────────────┐
|
||||
│ Repo │ Purpose │
|
||||
├──────────────┼──────────────────────────────────────────────┤
|
||||
│ jarvis-brain │ Original JSON-based brain (migration source) │
|
||||
├──────────────┼──────────────────────────────────────────────┤
|
||||
│ MoltBot │ Stock messaging gateway │
|
||||
└──────────────┴──────────────────────────────────────────────┘
|
||||
---
|
||||
Mosaic Stack v0.0.x — Building the future of personal assistants.
|
||||
18
apps/api/.swcrc
Normal file
18
apps/api/.swcrc
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"sourceMaps": true,
|
||||
"jsc": {
|
||||
"target": "es2022",
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"decorators": true
|
||||
},
|
||||
"transform": {
|
||||
"legacyDecorator": true,
|
||||
"decoratorMetadata": true
|
||||
},
|
||||
"keepClassNames": true
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
}
|
||||
}
|
||||
8
apps/api/nest-cli.json
Normal file
8
apps/api/nest-cli.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
||||
40
apps/api/package.json
Normal file
40
apps/api/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@mosaic/api",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"dev": "nest start --watch",
|
||||
"start": "node dist/main",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
"start:prod": "node dist/main",
|
||||
"lint": "eslint \"src/**/*.ts\"",
|
||||
"lint:fix": "eslint \"src/**/*.ts\" --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rm -rf dist",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:coverage": "vitest run --coverage",
|
||||
"test:e2e": "vitest run --config ./vitest.e2e.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^11.1.12",
|
||||
"@nestjs/core": "^11.1.12",
|
||||
"@nestjs/platform-express": "^11.1.12",
|
||||
"@mosaic/shared": "workspace:*",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mosaic/config": "workspace:*",
|
||||
"@nestjs/cli": "^11.0.6",
|
||||
"@nestjs/schematics": "^11.0.1",
|
||||
"@nestjs/testing": "^11.1.12",
|
||||
"@swc/core": "^1.10.18",
|
||||
"@types/express": "^5.0.1",
|
||||
"@types/node": "^22.13.4",
|
||||
"typescript": "^5.8.2",
|
||||
"unplugin-swc": "^1.5.2",
|
||||
"vitest": "^3.0.8"
|
||||
}
|
||||
}
|
||||
14
apps/api/src/app.controller.d.ts
vendored
Normal file
14
apps/api/src/app.controller.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import { AppService } from "./app.service";
|
||||
import type { ApiResponse } from "@mosaic/shared/types";
|
||||
interface HealthStatus {
|
||||
status: string;
|
||||
timestamp: string;
|
||||
}
|
||||
export declare class AppController {
|
||||
private readonly appService;
|
||||
constructor(appService: AppService);
|
||||
getHello(): string;
|
||||
getHealth(): ApiResponse<HealthStatus>;
|
||||
}
|
||||
export {};
|
||||
//# sourceMappingURL=app.controller.d.ts.map
|
||||
1
apps/api/src/app.controller.d.ts.map
Normal file
1
apps/api/src/app.controller.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.controller.d.ts","sourceRoot":"","sources":["app.controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBACa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,UAAU;IAGnD,QAAQ,IAAI,MAAM;IAKlB,SAAS,IAAI,WAAW,CAAC,YAAY,CAAC;CASvC"}
|
||||
50
apps/api/src/app.controller.js
Normal file
50
apps/api/src/app.controller.js
Normal file
@@ -0,0 +1,50 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const app_service_1 = require("./app.service");
|
||||
let AppController = class AppController {
|
||||
appService;
|
||||
constructor(appService) {
|
||||
this.appService = appService;
|
||||
}
|
||||
getHello() {
|
||||
return this.appService.getHello();
|
||||
}
|
||||
getHealth() {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
status: "healthy",
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.AppController = AppController;
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", String)
|
||||
], AppController.prototype, "getHello", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)("health"),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Object)
|
||||
], AppController.prototype, "getHealth", null);
|
||||
exports.AppController = AppController = __decorate([
|
||||
(0, common_1.Controller)(),
|
||||
__metadata("design:paramtypes", [app_service_1.AppService])
|
||||
], AppController);
|
||||
//# sourceMappingURL=app.controller.js.map
|
||||
1
apps/api/src/app.controller.js.map
Normal file
1
apps/api/src/app.controller.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.controller.js","sourceRoot":"","sources":["app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAiD;AACjD,+CAA2C;AASpC,IAAM,aAAa,GAAnB,MAAM,aAAa;IACK;IAA7B,YAA6B,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAAG,CAAC;IAGvD,QAAQ;QACN,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;IAGD,SAAS;QACP,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ,MAAM,EAAE,SAAS;gBACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAlBY,sCAAa;AAIxB;IADC,IAAA,YAAG,GAAE;;;;6CAGL;AAGD;IADC,IAAA,YAAG,EAAC,QAAQ,CAAC;;;;8CASb;wBAjBU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAE8B,wBAAU;GADxC,aAAa,CAkBzB"}
|
||||
31
apps/api/src/app.controller.test.ts
Normal file
31
apps/api/src/app.controller.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { AppService } from "./app.service";
|
||||
import { AppController } from "./app.controller";
|
||||
|
||||
describe("AppController", () => {
|
||||
const appService = new AppService();
|
||||
const controller = new AppController(appService);
|
||||
|
||||
describe("getHello", () => {
|
||||
it('should return "Mosaic Stack API"', () => {
|
||||
expect(controller.getHello()).toBe("Mosaic Stack API");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getHealth", () => {
|
||||
it("should return health status", () => {
|
||||
const result = controller.getHealth();
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.data.status).toBe("healthy");
|
||||
expect(result.data.timestamp).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("AppService", () => {
|
||||
const service = new AppService();
|
||||
|
||||
it('should return "Mosaic Stack API"', () => {
|
||||
expect(service.getHello()).toBe("Mosaic Stack API");
|
||||
});
|
||||
});
|
||||
29
apps/api/src/app.controller.ts
Normal file
29
apps/api/src/app.controller.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Controller, Get } from "@nestjs/common";
|
||||
import { AppService } from "./app.service";
|
||||
import type { ApiResponse } from "@mosaic/shared";
|
||||
|
||||
interface HealthStatus {
|
||||
status: string;
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
getHello(): string {
|
||||
return this.appService.getHello();
|
||||
}
|
||||
|
||||
@Get("health")
|
||||
getHealth(): ApiResponse<HealthStatus> {
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
status: "healthy",
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
3
apps/api/src/app.module.d.ts
vendored
Normal file
3
apps/api/src/app.module.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export declare class AppModule {
|
||||
}
|
||||
//# sourceMappingURL=app.module.d.ts.map
|
||||
1
apps/api/src/app.module.d.ts.map
Normal file
1
apps/api/src/app.module.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.module.d.ts","sourceRoot":"","sources":["app.module.ts"],"names":[],"mappings":"AAIA,qBAKa,SAAS;CAAG"}
|
||||
23
apps/api/src/app.module.js
Normal file
23
apps/api/src/app.module.js
Normal file
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const app_controller_1 = require("./app.controller");
|
||||
const app_service_1 = require("./app.service");
|
||||
let AppModule = class AppModule {
|
||||
};
|
||||
exports.AppModule = AppModule;
|
||||
exports.AppModule = AppModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [],
|
||||
controllers: [app_controller_1.AppController],
|
||||
providers: [app_service_1.AppService],
|
||||
})
|
||||
], AppModule);
|
||||
//# sourceMappingURL=app.module.js.map
|
||||
1
apps/api/src/app.module.js.map
Normal file
1
apps/api/src/app.module.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,qDAAiD;AACjD,+CAA2C;AAOpC,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IALrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,CAAC,8BAAa,CAAC;QAC5B,SAAS,EAAE,CAAC,wBAAU,CAAC;KACxB,CAAC;GACW,SAAS,CAAG"}
|
||||
10
apps/api/src/app.module.ts
Normal file
10
apps/api/src/app.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { AppController } from "./app.controller";
|
||||
import { AppService } from "./app.service";
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
export class AppModule {}
|
||||
4
apps/api/src/app.service.d.ts
vendored
Normal file
4
apps/api/src/app.service.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export declare class AppService {
|
||||
getHello(): string;
|
||||
}
|
||||
//# sourceMappingURL=app.service.d.ts.map
|
||||
1
apps/api/src/app.service.d.ts.map
Normal file
1
apps/api/src/app.service.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.service.d.ts","sourceRoot":"","sources":["app.service.ts"],"names":[],"mappings":"AAEA,qBACa,UAAU;IACrB,QAAQ,IAAI,MAAM;CAGnB"}
|
||||
20
apps/api/src/app.service.js
Normal file
20
apps/api/src/app.service.js
Normal file
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
let AppService = class AppService {
|
||||
getHello() {
|
||||
return "Mosaic Stack API";
|
||||
}
|
||||
};
|
||||
exports.AppService = AppService;
|
||||
exports.AppService = AppService = __decorate([
|
||||
(0, common_1.Injectable)()
|
||||
], AppService);
|
||||
//# sourceMappingURL=app.service.js.map
|
||||
1
apps/api/src/app.service.js.map
Normal file
1
apps/api/src/app.service.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.service.js","sourceRoot":"","sources":["app.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAGrC,IAAM,UAAU,GAAhB,MAAM,UAAU;IACrB,QAAQ;QACN,OAAO,kBAAkB,CAAC;IAC5B,CAAC;CACF,CAAA;AAJY,gCAAU;qBAAV,UAAU;IADtB,IAAA,mBAAU,GAAE;GACA,UAAU,CAItB"}
|
||||
8
apps/api/src/app.service.ts
Normal file
8
apps/api/src/app.service.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
getHello(): string {
|
||||
return "Mosaic Stack API";
|
||||
}
|
||||
}
|
||||
2
apps/api/src/main.d.ts
vendored
Normal file
2
apps/api/src/main.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=main.d.ts.map
|
||||
1
apps/api/src/main.d.ts.map
Normal file
1
apps/api/src/main.d.ts.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":""}
|
||||
16
apps/api/src/main.js
Normal file
16
apps/api/src/main.js
Normal file
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core_1 = require("@nestjs/core");
|
||||
const app_module_1 = require("./app.module");
|
||||
async function bootstrap() {
|
||||
const app = await core_1.NestFactory.create(app_module_1.AppModule);
|
||||
app.enableCors();
|
||||
const port = process.env["PORT"] ?? 3001;
|
||||
await app.listen(port);
|
||||
console.log(`API running on http://localhost:${port}`);
|
||||
}
|
||||
bootstrap().catch((err) => {
|
||||
console.error("Failed to start application:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
//# sourceMappingURL=main.js.map
|
||||
1
apps/api/src/main.js.map
Normal file
1
apps/api/src/main.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAChD,GAAG,CAAC,UAAU,EAAE,CAAC;IAEjB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC;IACzC,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC,mCAAmC,IAAI,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IACjC,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
||||
17
apps/api/src/main.ts
Normal file
17
apps/api/src/main.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NestFactory } from "@nestjs/core";
|
||||
import { AppModule } from "./app.module";
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
app.enableCors();
|
||||
|
||||
const port = process.env["PORT"] ?? 3001;
|
||||
await app.listen(port);
|
||||
|
||||
console.log(`API running on http://localhost:${port}`);
|
||||
}
|
||||
|
||||
bootstrap().catch((err: unknown) => {
|
||||
console.error("Failed to start application:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
13
apps/api/tsconfig.json
Normal file
13
apps/api/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "@mosaic/config/typescript/nestjs",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
|
||||
}
|
||||
27
apps/api/vitest.config.ts
Normal file
27
apps/api/vitest.config.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import swc from "unplugin-swc";
|
||||
import { defineConfig } from "vitest/config";
|
||||
import path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: false,
|
||||
environment: "node",
|
||||
include: ["src/**/*.test.ts", "src/**/*.spec.ts"],
|
||||
coverage: {
|
||||
provider: "v8",
|
||||
reporter: ["text", "json", "html"],
|
||||
exclude: ["node_modules/", "dist/"],
|
||||
},
|
||||
setupFiles: ["./vitest.setup.ts"],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
swc.vite({
|
||||
module: { type: "es6" },
|
||||
}),
|
||||
],
|
||||
});
|
||||
1
apps/api/vitest.setup.ts
Normal file
1
apps/api/vitest.setup.ts
Normal file
@@ -0,0 +1 @@
|
||||
import "reflect-metadata";
|
||||
6
apps/web/next-env.d.ts
vendored
Normal file
6
apps/web/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
7
apps/web/next.config.ts
Normal file
7
apps/web/next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
transpilePackages: ["@mosaic/ui", "@mosaic/shared"],
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
36
apps/web/package.json
Normal file
36
apps/web/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "@mosaic/web",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev --turbopack --port 3000",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"lint:fix": "next lint --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rm -rf .next",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:coverage": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mosaic/shared": "workspace:*",
|
||||
"@mosaic/ui": "workspace:*",
|
||||
"next": "^16.1.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mosaic/config": "workspace:*",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@types/node": "^22.13.4",
|
||||
"@types/react": "^19.0.8",
|
||||
"@types/react-dom": "^19.0.3",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"jsdom": "^26.0.0",
|
||||
"typescript": "^5.8.2",
|
||||
"vitest": "^3.0.8"
|
||||
}
|
||||
}
|
||||
20
apps/web/src/app/globals.css
Normal file
20
apps/web/src/app/globals.css
Normal file
@@ -0,0 +1,20 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-rgb: 255, 255, 255;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--background-rgb: 0, 0, 0;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
color: rgb(var(--foreground-rgb));
|
||||
background: rgb(var(--background-rgb));
|
||||
}
|
||||
16
apps/web/src/app/layout.tsx
Normal file
16
apps/web/src/app/layout.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { Metadata } from "next";
|
||||
import type { ReactNode } from "react";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Mosaic Stack",
|
||||
description: "Mosaic Stack Web Application",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
22
apps/web/src/app/page.test.tsx
Normal file
22
apps/web/src/app/page.test.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { describe, expect, it, afterEach } from "vitest";
|
||||
import { render, screen, cleanup } from "@testing-library/react";
|
||||
import Home from "./page";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
describe("Home", () => {
|
||||
it("should render the title", () => {
|
||||
render(<Home />);
|
||||
expect(screen.getByRole("heading", { level: 1 })).toHaveTextContent("Mosaic Stack");
|
||||
});
|
||||
|
||||
it("should render the buttons", () => {
|
||||
render(<Home />);
|
||||
const buttons = screen.getAllByRole("button");
|
||||
expect(buttons.length).toBe(2);
|
||||
expect(buttons[0]).toHaveTextContent("Get Started");
|
||||
expect(buttons[1]).toHaveTextContent("Learn More");
|
||||
});
|
||||
});
|
||||
16
apps/web/src/app/page.tsx
Normal file
16
apps/web/src/app/page.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@mosaic/ui";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center p-24">
|
||||
<h1 className="text-4xl font-bold mb-8">Mosaic Stack</h1>
|
||||
<p className="text-lg text-gray-600 mb-8">
|
||||
Welcome to the Mosaic Stack monorepo
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<Button variant="primary">Get Started</Button>
|
||||
<Button variant="secondary">Learn More</Button>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
11
apps/web/tsconfig.json
Normal file
11
apps/web/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "@mosaic/config/typescript/nextjs",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
23
apps/web/vitest.config.ts
Normal file
23
apps/web/vitest.config.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
import path from "path";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
globals: false,
|
||||
environment: "jsdom",
|
||||
include: ["src/**/*.test.tsx", "src/**/*.test.ts"],
|
||||
coverage: {
|
||||
provider: "v8",
|
||||
reporter: ["text", "json", "html"],
|
||||
exclude: ["node_modules/", ".next/"],
|
||||
},
|
||||
setupFiles: ["./vitest.setup.ts"],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
});
|
||||
1
apps/web/vitest.setup.ts
Normal file
1
apps/web/vitest.setup.ts
Normal file
@@ -0,0 +1 @@
|
||||
import "@testing-library/jest-dom/vitest";
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/.prettierrc.js
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:21:58
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-.prettierrc.js_20260128-1321_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.controller.test.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:44
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.controller.test.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.controller.test.ts
|
||||
**Tool Used:** Edit
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:27:46
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.controller.test.ts_20260128-1327_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.controller.test.ts
|
||||
**Tool Used:** Edit
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:28:44
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.controller.test.ts_20260128-1328_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.controller.test.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:29:44
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.controller.test.ts_20260128-1329_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.controller.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:34
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.controller.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.controller.ts
|
||||
**Tool Used:** Edit
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:26:43
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.controller.ts_20260128-1326_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.module.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:33
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.module.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/app.service.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:35
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-app.service.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/src/main.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:32
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-src-main.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/vitest.config.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:46
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-vitest.config.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/vitest.config.ts
|
||||
**Tool Used:** Edit
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:28:15
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-vitest.config.ts_20260128-1328_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/api/vitest.setup.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:28:13
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-api-vitest.setup.ts_20260128-1328_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/next-env.d.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:21:10
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-next-env.d.ts_20260128-1321_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/next.config.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:21:08
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-next.config.ts_20260128-1321_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/app/layout.tsx
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:21:23
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-app-layout.tsx_20260128-1321_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/app/page.test.tsx
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:27:21
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-app-page.test.tsx_20260128-1327_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/app/page.test.tsx
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:30:10
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-app-page.test.tsx_20260128-1330_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/src/app/page.tsx
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:21:24
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-src-app-page.tsx_20260128-1321_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/vitest.config.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:21:26
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-vitest.config.ts_20260128-1321_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/apps/web/vitest.setup.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:21:28
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-apps-web-vitest.setup.ts_20260128-1321_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/eslint.config.js
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:22:06
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-eslint.config.js_20260128-1322_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/config/eslint/base.js
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:18:48
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-config-eslint-base.js_20260128-1318_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/config/eslint/nestjs.js
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:18:49
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-config-eslint-nestjs.js_20260128-1318_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/config/eslint/nextjs.js
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:18:48
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-config-eslint-nextjs.js_20260128-1318_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/config/prettier/index.js
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:18:50
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-config-prettier-index.js_20260128-1318_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/shared/src/index.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:26:18
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-shared-src-index.ts_20260128-1326_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/shared/src/types/index.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:19:23
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-shared-src-types-index.ts_20260128-1319_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/shared/src/utils/index.test.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:19:25
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-shared-src-utils-index.test.ts_20260128-1319_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/shared/src/utils/index.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:19:24
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-shared-src-utils-index.ts_20260128-1319_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/shared/vitest.config.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:19:25
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-shared-vitest.config.ts_20260128-1319_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/ui/src/components/Button.test.tsx
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:19:59
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-ui-src-components-Button.test.tsx_20260128-1319_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/ui/src/components/Button.test.tsx
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:30:08
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-ui-src-components-Button.test.tsx_20260128-1330_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/ui/src/components/Button.tsx
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:19:49
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-ui-src-components-Button.tsx_20260128-1319_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/ui/src/index.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:19:48
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-ui-src-index.ts_20260128-1319_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/ui/vitest.config.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:00
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-ui-vitest.config.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
@@ -0,0 +1,17 @@
|
||||
# QA Remediation Report
|
||||
|
||||
**File:** /home/localadmin/src/mosaic-stack/packages/ui/vitest.setup.ts
|
||||
**Tool Used:** Write
|
||||
**Epic:** general
|
||||
**Iteration:** 1
|
||||
**Generated:** 2026-01-28 13:20:01
|
||||
|
||||
## Status
|
||||
Pending QA validation
|
||||
|
||||
## Next Steps
|
||||
This report was created by the QA automation hook.
|
||||
To process this report, run:
|
||||
```bash
|
||||
claude -p "Use Task tool to launch universal-qa-agent for report: /home/localadmin/src/mosaic-stack/docs/reports/qa-automation/pending/home-localadmin-src-mosaic-stack-packages-ui-vitest.setup.ts_20260128-1320_1_remediation_needed.md"
|
||||
```
|
||||
97
docs/scratchpads/1-project-scaffold.md
Normal file
97
docs/scratchpads/1-project-scaffold.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Issue #1: Project scaffold (monorepo, NestJS, Next.js 16)
|
||||
|
||||
## Objective
|
||||
Set up the monorepo structure with pnpm workspaces + TurboRepo containing:
|
||||
- apps/api (NestJS)
|
||||
- apps/web (Next.js 16)
|
||||
- packages/shared (types, utilities)
|
||||
- packages/ui (shared components)
|
||||
- packages/config (shared configuration)
|
||||
|
||||
## Requirements
|
||||
- pnpm workspace configuration
|
||||
- TurboRepo for build orchestration
|
||||
- TypeScript strict mode
|
||||
- ESLint + Prettier
|
||||
- Vitest for unit tests
|
||||
- Initial package.json scripts
|
||||
|
||||
## Approach
|
||||
1. Initialize root package.json with pnpm workspaces
|
||||
2. Configure TurboRepo (turbo.json)
|
||||
3. Set up shared packages first (config, shared, ui)
|
||||
4. Create NestJS API app
|
||||
5. Create Next.js 16 web app
|
||||
6. Configure TypeScript, ESLint, Prettier at root level
|
||||
7. Set up Vitest for testing
|
||||
8. Add build/dev/test scripts
|
||||
|
||||
## Progress
|
||||
- [x] Initialize pnpm workspace configuration
|
||||
- [x] Set up TurboRepo for build orchestration
|
||||
- [x] Create packages/config
|
||||
- [x] Create packages/shared
|
||||
- [x] Create packages/ui
|
||||
- [x] Create apps/api (NestJS)
|
||||
- [x] Create apps/web (Next.js 16)
|
||||
- [x] Configure TypeScript strict mode
|
||||
- [x] Set up ESLint + Prettier
|
||||
- [x] Configure Vitest
|
||||
- [x] Add initial package.json scripts
|
||||
- [x] Test build and verify
|
||||
|
||||
## Testing Results
|
||||
- `pnpm build` - All 4 packages build successfully
|
||||
- `pnpm test` - All 19 tests pass (shared: 10, api: 3, ui: 4, web: 2)
|
||||
|
||||
## Structure Created
|
||||
```
|
||||
mosaic-stack/
|
||||
├── apps/
|
||||
│ ├── api/ # NestJS 11.1.12 API
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── main.ts
|
||||
│ │ │ ├── app.module.ts
|
||||
│ │ │ ├── app.controller.ts
|
||||
│ │ │ └── app.service.ts
|
||||
│ │ └── package.json
|
||||
│ └── web/ # Next.js 16.1.6 with App Router
|
||||
│ ├── src/app/
|
||||
│ │ ├── layout.tsx
|
||||
│ │ ├── page.tsx
|
||||
│ │ └── globals.css
|
||||
│ └── package.json
|
||||
├── packages/
|
||||
│ ├── config/ # Shared TypeScript, ESLint, Prettier configs
|
||||
│ │ ├── typescript/
|
||||
│ │ ├── eslint/
|
||||
│ │ └── prettier/
|
||||
│ ├── shared/ # Shared types and utilities
|
||||
│ │ └── src/
|
||||
│ │ ├── types/
|
||||
│ │ └── utils/
|
||||
│ └── ui/ # Shared React components
|
||||
│ └── src/
|
||||
│ └── components/
|
||||
├── package.json # Root package.json with scripts
|
||||
├── pnpm-workspace.yaml # Workspace configuration
|
||||
├── turbo.json # TurboRepo configuration
|
||||
├── tsconfig.json # Root TypeScript config
|
||||
├── eslint.config.js # Root ESLint config
|
||||
└── .prettierrc.js # Root Prettier config
|
||||
```
|
||||
|
||||
## Key Scripts
|
||||
- `pnpm dev` - Start all dev servers (API: 3001, Web: 3000)
|
||||
- `pnpm build` - Build all packages
|
||||
- `pnpm test` - Run all tests
|
||||
- `pnpm lint` - Run linting
|
||||
- `pnpm format` - Format all files
|
||||
|
||||
## Notes
|
||||
- Version: 0.0.1 (M1-Foundation milestone)
|
||||
- Using pnpm 10.19.0 for package management
|
||||
- TurboRepo 2.8.0 for efficient build caching
|
||||
- Next.js 16.1.6 with Turbopack for dev
|
||||
- NestJS 11.1.12 with Vitest for testing
|
||||
- TypeScript 5.8.2 in strict mode
|
||||
13
eslint.config.js
Normal file
13
eslint.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import baseConfig from "@mosaic/config/eslint/base";
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.json", "./apps/*/tsconfig.json", "./packages/*/tsconfig.json"],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
34
package.json
Normal file
34
package.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "mosaic-stack",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@10.19.0",
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"dev": "turbo run dev",
|
||||
"lint": "turbo run lint",
|
||||
"lint:fix": "turbo run lint:fix",
|
||||
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
||||
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\"",
|
||||
"test": "turbo run test",
|
||||
"test:watch": "turbo run test:watch",
|
||||
"test:coverage": "turbo run test:coverage",
|
||||
"clean": "turbo run clean && rm -rf node_modules",
|
||||
"typecheck": "turbo run typecheck"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.0",
|
||||
"@typescript-eslint/parser": "^8.26.0",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-config-prettier": "^10.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"prettier": "^3.5.3",
|
||||
"turbo": "^2.8.0",
|
||||
"typescript": "^5.8.2",
|
||||
"vitest": "^3.0.8"
|
||||
}
|
||||
}
|
||||
32
packages/config/eslint/base.js
Normal file
32
packages/config/eslint/base.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import prettierConfig from "eslint-config-prettier";
|
||||
import prettierPlugin from "eslint-plugin-prettier";
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.strictTypeChecked,
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
prettierConfig,
|
||||
{
|
||||
plugins: {
|
||||
prettier: prettierPlugin,
|
||||
},
|
||||
rules: {
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{ prefer: "type-imports" },
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/coverage/**"],
|
||||
}
|
||||
);
|
||||
12
packages/config/eslint/nestjs.js
Normal file
12
packages/config/eslint/nestjs.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import baseConfig from "./base.js";
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
{
|
||||
rules: {
|
||||
"@typescript-eslint/interface-name-prefix": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
},
|
||||
},
|
||||
];
|
||||
17
packages/config/eslint/nextjs.js
Normal file
17
packages/config/eslint/nextjs.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import baseConfig from "./base.js";
|
||||
|
||||
export default [
|
||||
...baseConfig,
|
||||
{
|
||||
rules: {
|
||||
"@typescript-eslint/no-misused-promises": [
|
||||
"error",
|
||||
{
|
||||
checksVoidReturn: {
|
||||
attributes: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
29
packages/config/package.json
Normal file
29
packages/config/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "@mosaic/config",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
"./typescript/base": "./typescript/base.json",
|
||||
"./typescript/nextjs": "./typescript/nextjs.json",
|
||||
"./typescript/nestjs": "./typescript/nestjs.json",
|
||||
"./typescript/library": "./typescript/library.json",
|
||||
"./eslint/base": "./eslint/base.js",
|
||||
"./eslint/nextjs": "./eslint/nextjs.js",
|
||||
"./eslint/nestjs": "./eslint/nestjs.js",
|
||||
"./prettier": "./prettier/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.0",
|
||||
"@typescript-eslint/parser": "^8.26.0",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-config-prettier": "^10.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"prettier": "^3.5.3",
|
||||
"typescript-eslint": "^8.26.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
13
packages/config/prettier/index.js
Normal file
13
packages/config/prettier/index.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/** @type {import("prettier").Config} */
|
||||
const config = {
|
||||
semi: true,
|
||||
singleQuote: false,
|
||||
tabWidth: 2,
|
||||
trailingComma: "es5",
|
||||
printWidth: 100,
|
||||
bracketSpacing: true,
|
||||
arrowParens: "always",
|
||||
endOfLine: "lf",
|
||||
};
|
||||
|
||||
export default config;
|
||||
30
packages/config/typescript/base.json
Normal file
30
packages/config/typescript/base.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictBindCallApply": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2022"]
|
||||
}
|
||||
}
|
||||
7
packages/config/typescript/library.json
Normal file
7
packages/config/typescript/library.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
}
|
||||
}
|
||||
12
packages/config/typescript/nestjs.json
Normal file
12
packages/config/typescript/nestjs.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"incremental": true,
|
||||
"target": "ES2022"
|
||||
}
|
||||
}
|
||||
18
packages/config/typescript/nextjs.json
Normal file
18
packages/config/typescript/nextjs.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||
"jsx": "preserve",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
40
packages/shared/package.json
Normal file
40
packages/shared/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@mosaic/shared",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.js",
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./types": {
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"require": "./dist/types/index.js",
|
||||
"import": "./dist/types/index.js"
|
||||
},
|
||||
"./utils": {
|
||||
"types": "./dist/utils/index.d.ts",
|
||||
"require": "./dist/utils/index.js",
|
||||
"import": "./dist/utils/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "eslint src/",
|
||||
"lint:fix": "eslint src/ --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rm -rf dist",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:coverage": "vitest run --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mosaic/config": "workspace:*",
|
||||
"typescript": "^5.8.2",
|
||||
"vitest": "^3.0.8"
|
||||
}
|
||||
}
|
||||
2
packages/shared/src/index.ts
Normal file
2
packages/shared/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./types/index";
|
||||
export * from "./utils/index";
|
||||
38
packages/shared/src/types/index.ts
Normal file
38
packages/shared/src/types/index.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Base entity type with common fields
|
||||
*/
|
||||
export interface BaseEntity {
|
||||
id: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* API response wrapper
|
||||
*/
|
||||
export interface ApiResponse<T> {
|
||||
data: T;
|
||||
success: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pagination parameters
|
||||
*/
|
||||
export interface PaginationParams {
|
||||
page: number;
|
||||
limit: number;
|
||||
sortBy?: string;
|
||||
sortOrder?: "asc" | "desc";
|
||||
}
|
||||
|
||||
/**
|
||||
* Paginated response
|
||||
*/
|
||||
export interface PaginatedResponse<T> {
|
||||
data: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
}
|
||||
61
packages/shared/src/utils/index.test.ts
Normal file
61
packages/shared/src/utils/index.test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { isDefined, parseDate, sleep, slugify } from "./index.js";
|
||||
|
||||
describe("parseDate", () => {
|
||||
it("should return undefined for null or undefined", () => {
|
||||
expect(parseDate(null)).toBeUndefined();
|
||||
expect(parseDate(undefined)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return the same Date object if passed a Date", () => {
|
||||
const date = new Date("2024-01-15");
|
||||
expect(parseDate(date)).toBe(date);
|
||||
});
|
||||
|
||||
it("should parse valid date strings", () => {
|
||||
const result = parseDate("2024-01-15");
|
||||
expect(result).toBeInstanceOf(Date);
|
||||
expect(result?.toISOString()).toContain("2024-01-15");
|
||||
});
|
||||
|
||||
it("should return undefined for invalid date strings", () => {
|
||||
expect(parseDate("not-a-date")).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("slugify", () => {
|
||||
it("should convert text to lowercase slug", () => {
|
||||
expect(slugify("Hello World")).toBe("hello-world");
|
||||
});
|
||||
|
||||
it("should handle special characters", () => {
|
||||
expect(slugify("Hello, World!")).toBe("hello-world");
|
||||
});
|
||||
|
||||
it("should trim leading and trailing hyphens", () => {
|
||||
expect(slugify(" Hello World ")).toBe("hello-world");
|
||||
});
|
||||
});
|
||||
|
||||
describe("sleep", () => {
|
||||
it("should resolve after the specified time", async () => {
|
||||
const start = Date.now();
|
||||
await sleep(50);
|
||||
const elapsed = Date.now() - start;
|
||||
expect(elapsed).toBeGreaterThanOrEqual(45);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isDefined", () => {
|
||||
it("should return false for null and undefined", () => {
|
||||
expect(isDefined(null)).toBe(false);
|
||||
expect(isDefined(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for defined values", () => {
|
||||
expect(isDefined(0)).toBe(true);
|
||||
expect(isDefined("")).toBe(true);
|
||||
expect(isDefined(false)).toBe(true);
|
||||
expect(isDefined({})).toBe(true);
|
||||
});
|
||||
});
|
||||
35
packages/shared/src/utils/index.ts
Normal file
35
packages/shared/src/utils/index.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Safely parse a date string or return undefined
|
||||
*/
|
||||
export function parseDate(value: string | Date | undefined | null): Date | undefined {
|
||||
if (!value) return undefined;
|
||||
if (value instanceof Date) return value;
|
||||
const parsed = new Date(value);
|
||||
return isNaN(parsed.getTime()) ? undefined : parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a simple slug from a string
|
||||
*/
|
||||
export function slugify(text: string): string {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^\w\s-]/g, "")
|
||||
.replace(/[\s_-]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep for a given number of milliseconds
|
||||
*/
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value is defined (not null or undefined)
|
||||
*/
|
||||
export function isDefined<T>(value: T | null | undefined): value is T {
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
12
packages/shared/tsconfig.json
Normal file
12
packages/shared/tsconfig.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "@mosaic/config/typescript/library",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"module": "CommonJS",
|
||||
"moduleResolution": "node",
|
||||
"lib": ["ES2022", "DOM"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||
}
|
||||
14
packages/shared/vitest.config.ts
Normal file
14
packages/shared/vitest.config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: false,
|
||||
environment: "node",
|
||||
include: ["src/**/*.test.ts"],
|
||||
coverage: {
|
||||
provider: "v8",
|
||||
reporter: ["text", "json", "html"],
|
||||
exclude: ["node_modules/", "dist/"],
|
||||
},
|
||||
},
|
||||
});
|
||||
42
packages/ui/package.json
Normal file
42
packages/ui/package.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"name": "@mosaic/ui",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
},
|
||||
"./components/*": {
|
||||
"types": "./dist/components/*.d.ts",
|
||||
"import": "./dist/components/*.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsc --watch",
|
||||
"lint": "eslint src/",
|
||||
"lint:fix": "eslint src/ --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rm -rf dist",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest",
|
||||
"test:coverage": "vitest run --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mosaic/config": "workspace:*",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.2.0",
|
||||
"@types/react": "^19.0.8",
|
||||
"jsdom": "^26.0.0",
|
||||
"typescript": "^5.8.2",
|
||||
"vitest": "^3.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0 || ^19.0.0"
|
||||
}
|
||||
}
|
||||
31
packages/ui/src/components/Button.test.tsx
Normal file
31
packages/ui/src/components/Button.test.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { describe, expect, it, afterEach } from "vitest";
|
||||
import { render, screen, cleanup } from "@testing-library/react";
|
||||
import { Button } from "./Button.js";
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
describe("Button", () => {
|
||||
it("should render children", () => {
|
||||
render(<Button>Click me</Button>);
|
||||
expect(screen.getByRole("button")).toHaveTextContent("Click me");
|
||||
});
|
||||
|
||||
it("should apply variant styles", () => {
|
||||
render(<Button variant="danger">Delete</Button>);
|
||||
const button = screen.getByRole("button");
|
||||
expect(button.className).toContain("bg-red-600");
|
||||
});
|
||||
|
||||
it("should apply size styles", () => {
|
||||
render(<Button size="lg">Large Button</Button>);
|
||||
const button = screen.getByRole("button");
|
||||
expect(button.className).toContain("px-6");
|
||||
});
|
||||
|
||||
it("should pass through additional props", () => {
|
||||
render(<Button disabled>Disabled</Button>);
|
||||
expect(screen.getByRole("button")).toBeDisabled();
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user