Skip to content

Instantly share code, notes, and snippets.

@dpaluy
Last active September 1, 2024 21:10
Show Gist options
  • Save dpaluy/097cb3171ddff7becfaddf1bbec51e5e to your computer and use it in GitHub Desktop.
Save dpaluy/097cb3171ddff7becfaddf1bbec51e5e to your computer and use it in GitHub Desktop.
Cursor Composer Prompts

Backend Setup Instructions

Use this guide to setup the backend for this project.

It uses Supabase, Drizzle ORM, and Server Actions.

Write the complete code for every step. Do not get lazy. Write everything that is needed.

Your goal is to completely finish the backend setup.

Helpful Links

If the user gets stuck, refer them to the following links:

Install Libraries

Make sure the user knows to install the following libraries:

npm i drizzle-orm dotenv postgres
npm i -D drizzle-kit

Setup Steps

  • Create a /db folder in the root of the project

  • Create a /types folder in the root of the project

  • Add a drizzle.config.ts file to the root of the project with the following code:

import { config } from "dotenv";
import { defineConfig } from "drizzle-kit";

config({ path: ".env.local" });

export default defineConfig({
schema: "./db/schema/index.ts",
out: "./db/migrations",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!
}
});
  • Add a file called db.ts to the /db folder with the following code:
import { config } from "dotenv";
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
import { exampleTable } from "./schema";

config({ path: ".env.local" });

const schema = {
exampleTable
};

const client = postgres(process.env.DATABASE_URL!);

export const db = drizzle(client, { schema });
  • Create 2 folders in the /db folder:

  • /schema

  • Add a file called index.ts to the /schema folder

  • /queries

  • Create an example table in the /schema folder called example-schema.ts with the following code:

import { integer, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";

export const exampleTable = pgTable("example", {
id: uuid("id").defaultRandom().primaryKey(),
name: text("name").notNull(),
age: integer("age").notNull(),
email: text("email").notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
.notNull()
.defaultNow()
.$onUpdate(() => new Date())
});

export type InsertExample = typeof exampleTable.$inferInsert;
export type SelectExample = typeof exampleTable.$inferSelect;
  • Export the example table in the /schema/index.ts file like so:
export * from "./example-schema";
  • Create a new file called example-queries.ts in the /queries folder with the following code:
"use server";

import { eq } from "drizzle-orm";
import { db } from "../db";
import { InsertExample, SelectExample } from "../schema/example-schema";
import { exampleTable } from "./../schema/example-schema";

export const createExample = async (data: InsertExample) => {
try {
const [newExample] = await db.insert(exampleTable).values(data).returning();
return newExample;
} catch (error) {
console.error("Error creating example:", error);
throw new Error("Failed to create example");
}
};

export const getExampleById = async (id: string) => {
try {
const example = await db.query.exampleTable.findFirst({
where: eq(http://exampleTable.id, id)
});
if (!example) {
throw new Error("Example not found");
}
return example;
} catch (error) {
console.error("Error getting example by ID:", error);
throw new Error("Failed to get example");
}
};

export const getAllExamples = async (): Promise<SelectExample[]> => {
return db.query.exampleTable.findMany();
};

export const updateExample = async (id: string, data: Partial<InsertExample>) => {
try {
const [updatedExample] = await db.update(exampleTable).set(data).where(eq(http://exampleTable.id, id)).returning();
return updatedExample;
} catch (error) {
console.error("Error updating example:", error);
throw new Error("Failed to update example");
}
};

export const deleteExample = async (id: string) => {
try {
await db.delete(exampleTable).where(eq(http://exampleTable.id, id));
} catch (error) {
console.error("Error deleting example:", error);
throw new Error("Failed to delete example");
}
};
  • In package.json, add the following scripts:
"scripts": {
"db:generate": "npx drizzle-kit generate",
"db:migrate": "npx drizzle-kit migrate"
}
  • Run the following command to generate the tables:
npm run db:generate
  • Run the following command to migrate the tables:
npm run db:migrate
  • Create a folder called /actions in the root of the project for server actions

  • Create folder called /types in the root of the project for shared types

  • Create a file called action-types.ts in the /types/actions folder for server action types with the following code:

  • Create file called /types/index.ts and export all the types from the /types folder like so:

export * from "./action-types";
  • Create a file called example-actions.ts in the /actions folder for the example table's actions:
"use server";

import { createExample, deleteExample, getAllExamples, getExampleById, updateExample } from "@/db/queries/example-queries";
import { InsertExample } from "@/db/schema/example-schema";
import { ActionState } from "@/types";
import { revalidatePath } from "next/cache";

export async function createExampleAction(data: InsertExample): Promise<ActionState> {
try {
const newExample = await createExample(data);
revalidatePath("/examples");
return { status: "success", message: "Example created successfully", data: newExample };
} catch (error) {
return { status: "error", message: "Failed to create example" };
}
}

export async function getExampleByIdAction(id: string): Promise<ActionState> {
try {
const example = await getExampleById(id);
return { status: "success", message: "Example retrieved successfully", data: example };
} catch (error) {
return { status: "error", message: "Failed to get example" };
}
}

export async function getAllExamplesAction(): Promise<ActionState> {
try {
const examples = await getAllExamples();
return { status: "success", message: "Examples retrieved successfully", data: examples };
} catch (error) {
return { status: "error", message: "Failed to get examples" };
}
}

export async function updateExampleAction(id: string, data: Partial<InsertExample>): Promise<ActionState> {
try {
const updatedExample = await updateExample(id, data);
revalidatePath("/examples");
return { status: "success", message: "Example updated successfully", data: updatedExample };
} catch (error) {
return { status: "error", message: "Failed to update example" };
}
}

export async function deleteExampleAction(id: string): Promise<ActionState> {
try {
await deleteExample(id);
revalidatePath("/examples");
return { status: "success", message: "Example deleted successfully" };
} catch (error) {
return { status: "error", message: "Failed to delete example" };
}
}
export type ActionState = {
status: "success" | "error";
message: string;
data?: any;
};
  • Implement the server actions in the /app/page.tsx file to allow for manual testing.

  • The backend is now setup.

Flux with Replicate Documentation

Use this guide to setup generating images with Flux and Replicate.

Write the complete code for every step. Do not get lazy. Write everything that is needed.

Your goal is to completely finish the feature.

Helpful Links

Required Environment Variables

Make sure the user has the following environment variables set:

  • REPLICATE_API_TOKEN=

Install Replicate

Make sure the user has the Replicate package installed:

npm install replicate

Setup Steps

Create a Replicate Client

This file should go in /lib/replicate.ts

import Replicate from "replicate";

const replicate = new Replicate({
auth: process.env.REPLICATE_API_TOKEN
});

Create a Server Action

This file should go in /actions/replicate-actions.ts

"use server";

import replicate from "@/lib/replicate";

export async function generateFluxImage(prompt: string) {
const input = {
prompt: prompt,
num_outputs: 1,
aspect_ratio: "1:1",
output_format: "webp",
output_quality: 80
};

const output = await http://replicate.run("black-forest-labs/flux-schnell", { input });
return output;
}

Build the Frontend

This file should go in /app/flux/page.tsx.

  • Create a form that takes a prompt
  • Create a button that calls the server action
  • Have a nice ui for when the image is blank or loading
  • Display the image that is returned
  • Have a button to generate a new image
  • Have a button to download the image

Frontend Instructions

Use this guide for frontend work in the project. It uses Next.js, Tailwind, Shadcn, and Framer Motion. Write the complete code for every step. Do not get lazy. Write everything that is needed. Your goal is to completely finish whatever the user asks for.

Steps

  • All new components should go in /components and be and be named like example-component.tsx unless otherwise specified unless otherwise
  • All new pages go in /app

Reminders

  • We use the Next.js 14 app router
  • Try and group components into folders

Requirements

  • All data fetching should be done in a server component and pass the data down as props
  • Client components (useState, hooks, etc) require that use client is set at the top of the file
  • useRouter should be imported from next/navigation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment