laconic-deployer-frontend/standards/blueprints/qwrk-laconic-migration-guide.md

27 KiB

QWRK-Laconic Turborepo Migration Technical Specification

Implementation Starting Points

This migration specification supports multiple entry points depending on the current state of your repository:

Scenario 1: New Repository Implementation

  • Follow all steps sequentially starting from "Repository Initialization"
  • Execute all setup commands to build the complete architecture from scratch

Scenario 2: Existing Repository Conversion

If the repository already exists but requires Turborepo integration:

  1. Preserve existing package structure and Git history
  2. Add Turborepo configuration (turbo.json, pnpm-workspace.yaml)
  3. Adapt existing packages to the recommended structure
  4. Integrate shared package dependencies
  5. Skip initialization steps that would conflict with existing setup

Scenario 3: Partial Turborepo Implementation

For repositories with partial Turborepo architecture:

  1. Audit existing configuration against this specification
  2. Upgrade task definitions to latest syntax (tasks vs legacy pipeline)
  3. Apply missing architectural components
  4. Align package structure with recommended patterns
  5. Integrate modular services approach

Prerequisite Validation

Run the following diagnostic commands to determine your starting point:

# Check for existing Turborepo configuration
[ -f turbo.json ] && echo "Existing turbo.json found, requires update" || echo "New turbo.json needed"

# Verify package manager
command -v pnpm >/dev/null 2>&1 && echo "pnpm installed" || echo "pnpm installation required"

# Check Next.js applications
find . -path "*/package.json" -exec grep -l "next" {} \; | xargs -I{} dirname {}

Architecture Overview

graph TD
    subgraph "qwrk-laconic-mono"
        subgraph "apps"
            LW[laconic-web]
            LD[laconic-deploy]
            D[docs]
        end
        
        subgraph "packages"
            UI[ui]
            Utils[utils]
            Services[services]
        end
        
        LW -->|imports| UI
        LW -->|imports| Utils
        LW -->|imports| Services
        LD -->|imports| UI
        LD -->|imports| Utils
        LD -->|imports| Services
        D -->|imports| UI
    end

Technology Stack

Component Technology Version
Monorepo Manager Turborepo 2.0.0+
Package Manager pnpm 8.15.1+
Frontend Framework Next.js 15.0.0+
Linting/Formatting Biome 1.9.0+
UI Framework Tailwind CSS 3.4.0+
GraphQL Client Apollo Client 3.9.5+
Type Safety TypeScript 5.3.3+
Testing Vitest 1.2.0+

Repository Structure

qwrk-laconic-mono/
├── apps/
│   ├── laconic-web/            # Next.js 15 application
│   │   ├── src/
│   │   │   ├── app/            # App Router 
│   │   │   ├── api/            # API Routes
│   │   │   │   └── graphql/    # GraphQL API endpoint
│   │   │   ├── components/     # App-specific components
│   │   │   ├── lib/            # App-specific utilities
│   │   │   ├── styles/         # Global styles
│   │   │   └── types/          # TypeScript types
│   ├── laconic-deploy/         # Migrated current frontend
│   └── docs/                   # Documentation site
├── packages/
│   ├── ui/                     # Shared UI components
│   │   ├── src/
│   │   │   ├── components/     # React components 
│   │   │   ├── hooks/          # UI-related hooks
│   │   │   ├── styles/         # Component styles
│   │   │   └── index.ts        # Entry point
│   ├── utils/                  # Shared utilities
│   │   ├── src/
│   │   │   ├── helpers/        # Helper functions
│   │   │   ├── constants/      # Shared constants
│   │   │   └── index.ts        # Entry point
│   └── services/               # Consolidated service modules
│       ├── src/
│       │   ├── graphql/        # GraphQL client
│       │   ├── deployer/       # Deployment service
│       │   └── index.ts        # Entry point
├── turbo.json                  # Turborepo configuration
├── pnpm-workspace.yaml         # PNPM workspace definition
├── biome.json                  # Biome configuration
├── .npmrc                      # NPM configuration
└── package.json                # Root package.json

Implementation Guide

1. Repository Initialization

New Repository Approach

# Initialize Turborepo with pnpm
pnpm dlx create-turbo@latest qwrk-laconic-mono --package-manager=pnpm
cd qwrk-laconic-mono

# Clean default structure
rm -rf apps/docs apps/web

Existing Repository Approach

# If repository already exists and initialized:
git clone <existing-repo-url> qwrk-laconic-mono
cd qwrk-laconic-mono

# Create workspace structure if not exists
mkdir -p apps packages

# Save existing structure (optional)
find . -maxdepth 2 -type d -not -path "*/\.*" -not -path "./node_modules" \
  -not -path "./apps" -not -path "./packages" > existing_directories.txt

# Create migration branch
git checkout -b feature/turborepo-migration

2. Configure Package Manager

# Configure pnpm
cat > .npmrc << EOL
shamefully-hoist=true
strict-peer-dependencies=false
auto-install-peers=true
node-linker=hoisted
resolution-mode=highest
EOL

# Configure workspace
cat > pnpm-workspace.yaml << EOL
packages:
  - 'apps/*'
  - 'packages/*'
EOL

3. Biome Configuration

# Install Biome
pnpm add -D -w @biomejs/biome

# Configure Biome
cat > biome.json << EOL
{
  "$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "correctness": {
        "useExhaustiveDependencies": "error"
      },
      "suspicious": {
        "noExplicitAny": "warn"
      },
      "style": {
        "noNonNullAssertion": "error"
      }
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingComma": "es5",
      "semicolons": "always"
    }
  }
}
EOL

4. Turborepo Configuration

# Configure Turborepo
cat > turbo.json << EOL
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "globalEnv": ["NODE_ENV", "PORT", "NEXT_PUBLIC_*"],
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true,
      "dependsOn": ["^build"]
    },
    "lint": {
      "outputs": []
    },
    "format": {
      "outputs": []
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"]
    },
    "clean": {
      "cache": false
    }
  }
}
EOL

5. Root Package Configuration

# Configure root package.json
cat > package.json << EOL
{
  "name": "qwrk-laconic-mono",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "lint": "turbo lint",
    "format": "biome format --write .",
    "test": "turbo test",
    "clean": "turbo clean && rm -rf node_modules"
  },
  "devDependencies": {
    "@biomejs/biome": "1.9.0",
    "turbo": "latest"
  },
  "packageManager": "pnpm@8.15.1"
}
EOL

6. Initialize Applications

# Create Next.js applications
pnpm dlx create-next-app@latest apps/laconic-web \
  --typescript \
  --tailwind \
  --app \
  --src-dir \
  --import-alias "@/*" \
  --use-pnpm

pnpm dlx create-next-app@latest apps/docs \
  --typescript \
  --tailwind \
  --app \
  --src-dir \
  --import-alias "@/*" \
  --use-pnpm

7. Configure laconic-deploy placeholder

# Create placeholder for existing frontend migration
mkdir -p apps/laconic-deploy
cd apps/laconic-deploy

# Initialize package.json
cat > package.json << EOL
{
  "name": "laconic-deploy",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "dev": "echo \"Not implemented yet\" && exit 0",
    "build": "echo \"Not implemented yet\" && exit 0",
    "lint": "echo \"Not implemented yet\" && exit 0",
    "clean": "rm -rf node_modules .turbo"
  }
}
EOL

cd ../..

8. Setup Shared Packages

8.1 UI Package

# Create UI package structure
mkdir -p packages/ui/{src,dist}
mkdir -p packages/ui/src/{components,hooks,styles}

# Create UI package.json
cat > packages/ui/package.json << EOL
{
  "name": "@qwrk/ui",
  "version": "0.0.1",
  "private": true,
  "type": "module",
  "exports": {
    ".": "./dist/index.js",
    "./styles.css": "./dist/index.css"
  },
  "types": "./dist/index.d.ts",
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "lint": "biome lint src/",
    "format": "biome format --write src/",
    "clean": "rm -rf .turbo node_modules dist"
  },
  "peerDependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "dependencies": {
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.1.0",
    "lucide-react": "^0.336.0",
    "tailwind-merge": "^2.2.1"
  },
  "devDependencies": {
    "@types/react": "^19.0.0",
    "autoprefixer": "^10.4.16",
    "postcss": "^8.4.31",
    "tailwindcss": "^3.3.5",
    "tsup": "^8.0.1",
    "typescript": "^5.3.3"
  }
}
EOL

# Create tsup configuration
cat > packages/ui/tsup.config.ts << EOL
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  dts: true,
  splitting: false,
  sourcemap: true,
  clean: true,
  external: ['react', 'react-dom'],
  treeshake: true,
  minify: true
});
EOL

# Create package entry point
cat > packages/ui/src/index.ts << EOL
export * from './components';
export * from './hooks';
EOL

# Create exports file
cat > packages/ui/src/components/index.ts << EOL
// Export components
EOL

cat > packages/ui/src/hooks/index.ts << EOL
// Export hooks
EOL

8.2 Utils Package

# Create Utils package structure
mkdir -p packages/utils/{src,dist}
mkdir -p packages/utils/src/{helpers,constants}

# Create Utils package.json
cat > packages/utils/package.json << EOL
{
  "name": "@qwrk/utils",
  "version": "0.0.1",
  "private": true,
  "type": "module",
  "exports": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "lint": "biome lint src/",
    "format": "biome format --write src/",
    "clean": "rm -rf .turbo node_modules dist"
  },
  "devDependencies": {
    "tsup": "^8.0.1",
    "typescript": "^5.3.3"
  }
}
EOL

# Create tsup configuration
cat > packages/utils/tsup.config.ts << EOL
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  dts: true,
  splitting: false,
  sourcemap: true,
  clean: true,
  treeshake: true
});
EOL

# Create package entry point
cat > packages/utils/src/index.ts << EOL
export * from './helpers';
export * from './constants';
EOL

# Create exports files
cat > packages/utils/src/helpers/index.ts << EOL
// Export helper functions
EOL

cat > packages/utils/src/constants/index.ts << EOL
// Export constants
EOL

8.3 Services Package

# Create Services package structure
mkdir -p packages/services/{src,dist}
mkdir -p packages/services/src/{graphql,deployer}

# Create Services package.json
cat > packages/services/package.json << EOL
{
  "name": "@qwrk/services",
  "version": "0.0.1",
  "private": true,
  "type": "module",
  "exports": {
    ".": "./dist/index.js",
    "./graphql": "./dist/graphql/index.js",
    "./deployer": "./dist/deployer/index.js"
  },
  "types": {
    ".": "./dist/index.d.ts",
    "./graphql": "./dist/graphql/index.d.ts",
    "./deployer": "./dist/deployer/index.d.ts"
  },
  "scripts": {
    "build": "tsup",
    "dev": "tsup --watch",
    "lint": "biome lint src/",
    "format": "biome format --write src/",
    "clean": "rm -rf .turbo node_modules dist"
  },
  "dependencies": {
    "@apollo/client": "^3.9.5",
    "graphql": "^16.8.1"
  },
  "devDependencies": {
    "tsup": "^8.0.1",
    "typescript": "^5.3.3"
  }
}
EOL

# Create tsup configuration
cat > packages/services/tsup.config.ts << EOL
import { defineConfig } from 'tsup';

export default defineConfig({
  entry: [
    'src/index.ts',
    'src/graphql/index.ts',
    'src/deployer/index.ts'
  ],
  format: ['esm'],
  dts: true,
  splitting: true,
  sourcemap: true,
  clean: true,
  treeshake: true
});
EOL

# Create package entry points
cat > packages/services/src/index.ts << EOL
export * from './graphql';
export * from './deployer';
EOL

cat > packages/services/src/graphql/index.ts << EOL
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

export function createApolloClient(apiUrl = '/api/graphql') {
  const httpLink = new HttpLink({
    uri: apiUrl,
  });

  const authLink = setContext((_, { headers }) => {
    // Get the authentication token from local storage if it exists
    const token = typeof window !== 'undefined' 
      ? localStorage.getItem('authToken') 
      : null;
      
    // Return the headers to the context so httpLink can read them
    return {
      headers: {
        ...headers,
        authorization: token ? \`Bearer \${token}\` : '',
      },
    };
  });

  return new ApolloClient({
    link: authLink.concat(httpLink),
    cache: new InMemoryCache(),
    defaultOptions: {
      watchQuery: {
        fetchPolicy: 'cache-and-network',
      },
    },
  });
}

// Export other GraphQL utilities
export * from './hooks';
export * from './fragments';
EOL

# Create placeholder files
cat > packages/services/src/graphql/hooks.ts << EOL
// GraphQL hooks
EOL

cat > packages/services/src/graphql/fragments.ts << EOL
// GraphQL fragments
EOL

cat > packages/services/src/deployer/index.ts << EOL
// Deployer service implementation
export interface DeployOptions {
  projectId: string;
  branch: string;
  commitHash: string;
}

export const deployProject = async (options: DeployOptions) => {
  // Implementation
};
EOL

9. Configure Next.js App

9.1 GraphQL API Route

# Create GraphQL API route
mkdir -p apps/laconic-web/src/app/api/graphql
mkdir -p apps/laconic-web/src/graphql

# Create route handler
cat > apps/laconic-web/src/app/api/graphql/route.ts << EOL
import { ApolloServer } from '@apollo/server';
import { startServerAndCreateNextHandler } from '@as-integrations/next';
import { typeDefs } from '@/graphql/schema';
import { resolvers } from '@/graphql/resolvers';

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

const handler = startServerAndCreateNextHandler(server, {
  context: async (req) => {
    // Extract user information from request headers or session
    const user = req.headers.get('authorization')?.replace('Bearer ', '');
    
    return {
      user,
    };
  },
});

export { handler as GET, handler as POST };
EOL

# Add package.json dependencies
cd apps/laconic-web
pnpm add @apollo/server @as-integrations/next graphql
cd ../..

9.2 GraphQL Schema and Resolvers

# Create GraphQL schema
cat > apps/laconic-web/src/graphql/schema.ts << EOL
import { gql } from 'graphql-tag';

export const typeDefs = gql\`
  enum Role {
    Owner
    Maintainer
    Reader
  }

  enum Permission {
    View
    Edit
  }

  enum Environment {
    Production
    Preview
    Development
  }

  enum DeploymentStatus {
    Building
    Ready
    Error
    Deleting
  }

  enum AuctionStatus {
    completed
    reveal
    commit
    expired
  }

  enum DomainStatus {
    Live
    Pending
  }

  type User {
    id: String!
    name: String
    email: String!
    organizations: [Organization!]
    projects: [Project!]
    isVerified: Boolean!
    createdAt: String!
    updatedAt: String!
    gitHubToken: String
  }

  type Organization {
    id: String!
    name: String!
    slug: String!
    projects: [Project!]
    createdAt: String!
    updatedAt: String!
    members: [OrganizationMember!]
  }

  type OrganizationMember {
    id: String!
    member: User!
    role: Role!
    createdAt: String!
    updatedAt: String!
  }

  type Project {
    id: String!
    owner: User!
    deployments: [Deployment!]
    name: String!
    repository: String!
    prodBranch: String!
    description: String
    deployers: [Deployer!]
    auctionId: String
    fundsReleased: Boolean
    template: String
    framework: String
    paymentAddress: String!
    txHash: String!
    webhooks: [String!]
    members: [ProjectMember!]
    environmentVariables: [EnvironmentVariable!]
    createdAt: String!
    updatedAt: String!
    organization: Organization!
    icon: String
    baseDomains: [String!]
  }

  # Rest of the schema types...

  type Query {
    user: User!
    organizations: [Organization!]
    projects: [Project!]
    projectsInOrganization(organizationSlug: String!): [Project!]
    project(projectId: String!): Project
    # Rest of the queries...
  }

  type Mutation {
    addProjectMember(projectId: String!, data: AddProjectMemberInput): Boolean!
    updateProjectMember(
      projectMemberId: String!
      data: UpdateProjectMemberInput
    ): Boolean!
    # Rest of the mutations...
  }
\`;
EOL

# Create resolvers
cat > apps/laconic-web/src/graphql/resolvers.ts << EOL
// Sample resolvers implementation
export const resolvers = {
  Query: {
    user: (_: any, __: any, context: any) => {
      // Return the authenticated user
      return context.user;
    },
    organizations: async (_: any, __: any, context: any) => {
      // Implement fetching organizations for the user
      return [];
    },
    // Implement other resolvers...
  },
  Mutation: {
    // Implement mutations...
  }
};
EOL

9.3 Authentication Setup

# Create authentication middleware
cat > apps/laconic-web/src/middleware.ts << EOL
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const authToken = request.cookies.get('authToken')?.value;
  const isAuthRoute = request.nextUrl.pathname.startsWith('/auth');
  const isApiRoute = request.nextUrl.pathname.startsWith('/api');

  if (!authToken && !isAuthRoute && !isApiRoute) {
    return NextResponse.redirect(new URL('/auth/login', request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
EOL

10. App Router Structure Implementation

# Create necessary directories for App Router
mkdir -p apps/laconic-web/src/app/{dashboard,projects,settings,auth}
mkdir -p apps/laconic-web/src/app/projects/create/\[step\]
mkdir -p apps/laconic-web/src/app/projects/\[id\]/{settings,branches}
mkdir -p apps/laconic-web/src/app/projects/\[id\]/branches/{create,\[branchId\]}
mkdir -p apps/laconic-web/src/app/auth/{login,register}

# Create root page
cat > apps/laconic-web/src/app/page.tsx << EOL
import { redirect } from 'next/navigation';

export default function Home() {
  redirect('/dashboard');
}
EOL

# Create dashboard page
cat > apps/laconic-web/src/app/dashboard/page.tsx << EOL
export default function DashboardPage() {
  return (
    <div>
      <h1>Dashboard</h1>
    </div>
  );
}
EOL

# Create loading and error states
cat > apps/laconic-web/src/app/dashboard/loading.tsx << EOL
export default function DashboardLoading() {
  return <div>Loading dashboard...</div>;
}
EOL

cat > apps/laconic-web/src/app/dashboard/error.tsx << EOL
'use client';

import { useEffect } from 'react';

export default function DashboardError({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error);
  }, [error]);

  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => reset()}>Try again</button>
    </div>
  );
}
EOL

# Create projects listing page
cat > apps/laconic-web/src/app/projects/page.tsx << EOL
export default function ProjectsPage() {
  return (
    <div>
      <h1>Projects</h1>
    </div>
  );
}
EOL

# Create project creation page
cat > apps/laconic-web/src/app/projects/create/page.tsx << EOL
export default function CreateProjectPage() {
  return (
    <div>
      <h1>Create Project</h1>
    </div>
  );
}
EOL

# Create project step page
cat > apps/laconic-web/src/app/projects/create/\[step\]/page.tsx << EOL
export default function CreateProjectStepPage({
  params,
}: {
  params: { step: string };
}) {
  return (
    <div>
      <h1>Create Project - Step {params.step}</h1>
    </div>
  );
}
EOL

# Create login page
cat > apps/laconic-web/src/app/auth/login/page.tsx << EOL
export default function LoginPage() {
  return (
    <div>
      <h1>Login</h1>
    </div>
  );
}
EOL

# Create register page 
cat > apps/laconic-web/src/app/auth/register/page.tsx << EOL
export default function RegisterPage() {
  return (
    <div>
      <h1>Register</h1>
    </div>
  );
}
EOL

Testing the Setup

  1. Install dependencies:
pnpm install
  1. Start the development server:
pnpm dev

Migration Strategy

flowchart TD
    A[Initialize Turborepo] --> B[Configure Biome & Packages]
    B --> C[Create Next.js Applications]
    C --> D[Set Up API Routes]
    D --> E[Implement GraphQL Client]
    E --> F[Port UI Components]
    F --> G[Implement App Router Structure]
    G --> H[Migrate Core Features]
    
    subgraph "Phase 1: Infrastructure"
        A
        B
        C
    end
    
    subgraph "Phase 2: API Layer"
        D
        E
    end
    
    subgraph "Phase 3: UI Migration"
        F
        G
    end
    
    subgraph "Phase 4: Application Logic"
        H
    end

Key Migration Tasks

  1. Infrastructure Setup:

    • Initialize Turborepo structure ✓
    • Configure Biome for linting/formatting ✓
    • Set up package structure ✓
  2. API Layer Implementation:

    • Migrate GraphQL schema ✓
    • Implement API routes ✓
    • Set up Apollo client ✓
  3. UI Component Migration:

    • Create shared UI package ✓
    • Port core UI components
    • Implement design system foundation
  4. Application Logic:

    • Implement authentication flow
    • Create project management features
    • Implement deployment functionality

Repository Structural Migration

For existing repositories that require Turborepo conversion, follow this structural migration approach:

flowchart TB
    subgraph "Initial State"
        A[Existing Repository]
        B[Frontend Application]
        C[Backend Services]
        D[Shared Libraries]
    end
    
    subgraph "Migration Process"
        E[Create Migration Branch]
        F[Add Turborepo Config]
        G[Restructure Packages]
        H[Refactor Dependencies]
        I[Implement Build System]
    end
    
    subgraph "Final State"
        J[apps/laconic-web]
        K[apps/laconic-deploy]
        L[apps/docs]
        M[packages/ui]
        N[packages/utils]
        O[packages/services]
    end
    
    A --> E
    E --> F
    F --> G
    G --> H
    H --> I
    I --> J & K & L & M & N & O

Repository Structure Analysis

Before migration, analyze the existing code structure:

# Identify package dependencies
find . -name "package.json" -not -path "*/node_modules/*" -exec jq -r '.dependencies | keys[]' {} \; | sort | uniq -c | sort -nr

# Identify file distribution
find . -type f -name "*.ts*" | grep -v "node_modules" | grep -v ".turbo" | grep -v "dist" | wc -l

# Analyze potential shared components
find . -type f -name "*.tsx" -not -path "*/node_modules/*" | xargs grep -l "export" | sort

Incremental Migration Strategy

  1. Coexistence Phase

    • Implement Turborepo alongside existing structure
    • Gradually move components to new architecture
    • Maintain backward compatibility during transition
  2. Dual Build System

    • Configure builds for both legacy and new structure
    • Implement feature flags for incremental adoption
    • Monitor performance metrics across both systems
  3. Final Migration

    • Complete transition to Turborepo architecture
    • Remove legacy configuration
    • Optimize build pipeline for new structure

Best Practices and Guidelines

TypeScript Configuration

Ensure strict type checking across all packages:

// tsconfig.json base configuration
{
  "compilerOptions": {
    "target": "ES2020",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ]
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}

GraphQL Code Generation

For type-safe GraphQL operations, integrate GraphQL Code Generator:

# Install GraphQL Code Generator
pnpm add -D -w @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-react-apollo

# Create codegen configuration
cat > codegen.ts << EOL
import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
  schema: 'apps/laconic-web/src/graphql/schema.ts',
  documents: ['apps/laconic-web/src/**/*.tsx', 'packages/services/src/**/*.ts'],
  generates: {
    'packages/services/src/graphql/generated/': {
      preset: 'client',
      plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'],
    },
  },
};

export default config;
EOL

# Add script to root package.json
# "codegen": "graphql-codegen"

Continuous Integration

Set up GitHub Actions workflow:

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v3
        with:
          version: 8.15.1
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      - name: Install dependencies
        run: pnpm install
      - name: Lint
        run: pnpm lint
      - name: Build
        run: pnpm build
      - name: Test
        run: pnpm test

Conclusion

This technical specification provides a comprehensive guide for migrating the qwrk-laconic repository to a modern Turborepo structure with Next.js 15. By following this guide, you can create a modular, maintainable monorepo that leverages the latest technologies and best practices for web development.

The migration approach prioritizes incremental adoption, allowing for gradual transition while maintaining backward compatibility with existing systems.