Skip to content

Production Readiness & Template Finalization

Objective

Finalize the template for production use with comprehensive documentation, scaffolding tools, and deployment configuration.

Background

Transform the working MVP into a reusable template that developers can clone and customize for their own projects.

Tasks

  • Create template scaffolding system
  • Add production Docker configurations
  • Set up CI/CD pipeline templates
  • Write comprehensive documentation
  • Create example application
  • Add deployment guides (Heroku, Digital Ocean, AWS)
  • Performance optimizations
  • Security hardening
  • Template customization tools

Template Scaffolding System

scripts/
├── scaffold.js              # Main scaffolding tool
├── templates/
│   ├── project-name/         # Project name replacements
│   ├── database-schema/      # Custom schema templates
│   └── component-library/    # UI component templates
├── questions.js              # Interactive setup questions
└── README-template.md        # Generated README

Scaffolding Tool

// scripts/scaffold.js
const inquirer = require('inquirer');
const fs = require('fs-extra');
const path = require('path');

const questions = [
  {
    type: 'input',
    name: 'projectName',
    message: 'What is your project name?',
    validate: input => input.length > 0
  },
  {
    type: 'input', 
    name: 'description',
    message: 'Project description:'
  },
  {
    type: 'confirm',
    name: 'includeMobile',
    message: 'Include React Native mobile app?',
    default: true
  },
  {
    type: 'list',
    name: 'database',
    message: 'Choose database schema:',
    choices: ['Task Management', 'E-commerce', 'Social Media', 'Custom']
  }
];

async function scaffold() {
  const answers = await inquirer.prompt(questions);
  
  // Copy template files with replacements
  await copyTemplate(answers);
  
  // Generate custom schema if needed
  if (answers.database === 'Custom') {
    await generateSchema(answers);
  }
  
  console.log(`✅ ${answers.projectName} created successfully\!`);
  console.log(`Next steps: cd ${answers.projectName} && npm run setup`);
}

Production Docker Configuration

# Dockerfile.production
FROM node:18-alpine AS builder

# Install OPAM and OCaml
RUN apk add --no-cache \
    build-base \
    opam \
    m4

# Set up OPAM
RUN opam init --disable-sandboxing -y
RUN opam switch create 5.3.0
RUN eval $(opam env)

# Install Melange and dependencies
COPY . /app
WORKDIR /app
RUN opam install --deps-only .
RUN opam exec -- dune build @melange

# Production stage
FROM nginx:alpine AS production
COPY --from=builder /app/_build/default/packages/web/src/*.js /usr/share/nginx/html/
COPY ./nginx.prod.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

CI/CD Pipeline Template

# .gitlab-ci-template.yml
stages:
  - build
  - test
  - security
  - deploy

variables:
  POSTGRES_DB: ${PROJECT_NAME}
  POSTGRES_USER: postgres
  POSTGRES_PASSWORD: postgres

build:
  stage: build
  script:
    - opam install --deps-only .
    - dune build @melange
    - npm run build:web
    - npm run build:mobile
  artifacts:
    paths:
      - _build/
      - packages/web/dist/
    expire_in: 1 hour

test:
  stage: test
  services:
    - postgres:15-alpine
  script:
    - dune build @test
    - npm run test:integration
    - npm run test:e2e
  coverage: '/Coverage: \d+\.\d+%/'

security-scan:
  stage: security
  script:
    - npm audit --audit-level high
    - opam exec -- dune exec -- semgrep --config=auto packages/
  allow_failure: true

deploy-staging:
  stage: deploy
  script:
    - docker build -f Dockerfile.production -t ${PROJECT_NAME}:${CI_COMMIT_SHA} .
    - docker push ${REGISTRY}/${PROJECT_NAME}:${CI_COMMIT_SHA}
  only:
    - develop

deploy-production:
  stage: deploy
  script:
    - docker build -f Dockerfile.production -t ${PROJECT_NAME}:${CI_COMMIT_SHA} .
    - docker push ${REGISTRY}/${PROJECT_NAME}:${CI_COMMIT_SHA}
    - kubectl apply -f k8s/
  only:
    - main
  when: manual

Documentation Structure

docs/
├── getting-started.md       # Quick start guide
├── architecture.md          # System architecture
├── database-design.md       # Database patterns
├── graphql-api.md          # API documentation
├── frontend-development.md  # React/ReasonML guides
├── mobile-development.md    # React Native guides
├── deployment/
│   ├── heroku.md
│   ├── digital-ocean.md
│   ├── aws.md
│   └── kubernetes.md
├── customization/
│   ├── adding-features.md
│   ├── styling-guide.md
│   └── database-migrations.md
└── troubleshooting.md

Example Application

(* examples/task-manager/src/components/DashboardExample.re *)

(* Comprehensive example showing all features *)
module GetDashboardData = [%graphql {|
  query GetDashboard {
    currentUser {
      id
      name
      teams {
        id
        name
        projects {
          id
          name
          tasks(first: 5) {
            id
            title
            status
            priority
          }
        }
      }
    }
  }
|}];

module Styles = {
  let dashboard = [%styled.div {|
    display: grid;
    grid-template-columns: 250px 1fr;
    height: 100vh;
    background: var(--background);
  |}];

  let sidebar = [%styled.aside {|
    background: var(--surface);
    border-right: 1px solid var(--border);
    padding: 1.5rem;
  |}];

  let main = [%styled.main {|
    padding: 2rem;
    overflow-y: auto;
  |}];
};

[@react.component]
let make = () => {
  let (result, _refetch) = useQuery(GetDashboardData.make());

  <Styles.dashboard>
    <Styles.sidebar>
      {result
       |> RemoteData.fold(
            () => <div> {React.string("Loading...")} </div>,
            _error => <div> {React.string("Error loading sidebar")} </div>,
            data =>
              <Navigation
                teams={data##currentUser##teams}
                currentUser={data##currentUser}
              />
          )}
    </Styles.sidebar>
    <Styles.main>
      {result
       |> RemoteData.fold(
            () => <LoadingSpinner />,
            error => <ErrorMessage error />,
            data => <ProjectOverview projects={data##currentUser##teams |> Array.flatMap(team => team##projects)} />
          )}
    </Styles.main>
  </Styles.dashboard>
};

Performance Optimizations

(* Performance optimization examples *)

(* Memoized components *)
module TaskItem = {
  [@react.component]
  let make = React.memo((~task, ~onUpdate) => {
    let handleClick = useCallback1(() => onUpdate(task.id), [|task.id|]);
    
    <div onClick=handleClick>
      {React.string(task.title)}
    </div>
  });
};

(* Optimized GraphQL queries *)
module GetTasksPaginated = [%graphql {|
  query GetTasks($first: Int\!, $after: String) {
    tasks(first: $first, after: $after) {
      edges {
        node {
          id
          title
          status
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
|}];

Security Hardening

-- Additional security policies
CREATE POLICY "Users can only see their own data"
ON app_public.users
FOR ALL
TO app_user
USING (id = app_public.current_user_id());

-- Rate limiting function
CREATE OR REPLACE FUNCTION app_private.rate_limit(
  identifier TEXT,
  max_requests INTEGER DEFAULT 100,
  window_seconds INTEGER DEFAULT 3600
) RETURNS BOOLEAN AS $$
DECLARE
  current_count INTEGER;
BEGIN
  -- Implementation of rate limiting logic
  RETURN current_count < max_requests;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

Deployment Guides

# Heroku Deployment

1. Install Heroku CLI
2. Configure buildpacks:
   ```bash
   heroku buildpacks:add https://github.com/ocaml/heroku-buildpack-ocaml
   heroku buildpacks:add heroku/nodejs
  1. Set environment variables:
    heroku config:set JWT_SECRET=your-secret
    heroku config:set DATABASE_URL=postgres://...
  2. Deploy:
    git push heroku main

## Package.json Scripts
```json
{
  "scripts": {
    "setup": "node scripts/scaffold.js",
    "dev": "concurrently \"dune build @melange --watch\" \"npm run dev:api\" \"npm run dev:web\"",
    "build": "dune build @melange && npm run build:web",
    "test": "dune runtest && npm run test:integration",
    "deploy": "npm run build && docker build -f Dockerfile.production .",
    "docs:serve": "mdbook serve docs/",
    "security:check": "npm audit && opam exec -- semgrep --config=auto ."
  }
}

Acceptance Criteria

  • Scaffolding tool creates working project
  • All deployment options documented and tested
  • CI/CD pipeline template works
  • Example application demonstrates all features
  • Performance benchmarks meet targets
  • Security scan passes
  • Documentation is comprehensive
  • Template can be customized easily

Priority: 🟡 Medium

Essential for template usability.

Estimated Effort: 4-5 days

Dependencies

  • All previous issues completed
  • Example application working end-to-end

CI Validation

  • Scaffolding tool works correctly
  • Generated projects build successfully
  • All deployment methods tested
  • Documentation builds and serves
  • Security scans pass