Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0c7777e7a | ||
|
|
a31d98b086 |
No files matched your search
@@ -73,6 +73,8 @@ Applied to About and every post. Recorded here so the voice does not drift.
|
|||||||
- State limits before someone else finds them. Every post that presents a
|
- State limits before someone else finds them. Every post that presents a
|
||||||
metric says what it does not show.
|
metric says what it does not show.
|
||||||
- No mission statements, no "passionate about", no invented team.
|
- No mission statements, no "passionate about", no invented team.
|
||||||
|
- No em dashes. One of the clearest tells of machine-written prose, which is
|
||||||
|
the exact problem this work exists to fix.
|
||||||
- Short sentences. The existing code comments in this repo are already written
|
- Short sentences. The existing code comments in this repo are already written
|
||||||
this way; the prose should match.
|
this way; the prose should match.
|
||||||
|
|
||||||
|
|||||||
@@ -40,5 +40,3 @@ yarn-error.log*
|
|||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
# Payload generates this from the config on every build
|
|
||||||
/payload-types.ts
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* The generated migration is schema-qualified to "payload" throughout but does
|
||||||
|
* not create that schema — `schemaName` says where tables go, it does not
|
||||||
|
* create anything. On staging and production, which have never run it, the
|
||||||
|
* whole migration fails with `schema "payload" does not exist`.
|
||||||
|
*
|
||||||
|
* The CREATE SCHEMA is therefore hand-added, which makes it exactly the kind
|
||||||
|
* of edit a regeneration silently discards. This is the guard.
|
||||||
|
*/
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const DIR = path.join(__dirname, '..', '..', 'migrations');
|
||||||
|
|
||||||
|
function migrationFiles() {
|
||||||
|
return fs
|
||||||
|
.readdirSync(DIR)
|
||||||
|
.filter((f) => f.endsWith('.ts') && f !== 'index.ts');
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('payload migrations', () => {
|
||||||
|
it('ships at least one migration, so a container has tables to find', () => {
|
||||||
|
expect(migrationFiles().length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates the payload schema before creating anything in it', () => {
|
||||||
|
const initial = migrationFiles().find((f) => f.includes('initial'))!;
|
||||||
|
const sql = fs.readFileSync(path.join(DIR, initial), 'utf8');
|
||||||
|
|
||||||
|
expect(sql).toMatch(/CREATE SCHEMA IF NOT EXISTS "payload"/);
|
||||||
|
|
||||||
|
// Ordering matters: the schema must be created before the first object
|
||||||
|
// that lives in it, or the migration fails on its first statement.
|
||||||
|
expect(sql.indexOf('CREATE SCHEMA IF NOT EXISTS "payload"'))
|
||||||
|
.toBeLessThan(sql.indexOf('CREATE TABLE "payload"'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('creates the tables the app queries on boot', () => {
|
||||||
|
const initial = migrationFiles().find((f) => f.includes('initial'))!;
|
||||||
|
const sql = fs.readFileSync(path.join(DIR, initial), 'utf8');
|
||||||
|
for (const table of ['users', 'posts', '_posts_v', 'media', 'payload_migrations']) {
|
||||||
|
expect(sql).toContain(`CREATE TABLE "payload"."${table}"`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('is wired into the adapter, so it runs on server init', () => {
|
||||||
|
const config = fs.readFileSync(
|
||||||
|
path.join(__dirname, '..', '..', 'payload.config.ts'), 'utf8',
|
||||||
|
);
|
||||||
|
expect(config).toMatch(/prodMigrations:\s*migrations/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -42,7 +42,7 @@ export default function AboutPage() {
|
|||||||
<div className={styles.prose}>
|
<div className={styles.prose}>
|
||||||
<p className={styles.lede}>
|
<p className={styles.lede}>
|
||||||
I'm a parent in south-west London. When we started looking at
|
I'm a parent in south-west London. When we started looking at
|
||||||
primary schools, I found the information I needed was all published —
|
primary schools, I found the information I needed was all published,
|
||||||
and almost impossible to hold in one place.
|
and almost impossible to hold in one place.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -68,11 +68,11 @@ export default function AboutPage() {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
What I do have is the problem itself — I'm going through primary
|
What I do have is the problem itself. I'm going through primary
|
||||||
admissions right now — and a working knowledge of data, which is what
|
admissions right now, and I work with data for a living. That
|
||||||
I do for a living. That combination is enough to take published
|
combination is enough to take published figures and present them
|
||||||
figures and present them honestly. It is not enough to tell you which
|
honestly. It is not enough to tell you which school is right for your
|
||||||
school is right for your child, and this site never tries to.
|
child, and this site never tries to.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 className={styles.subheading}>Where the numbers come from</h2>
|
<h2 className={styles.subheading}>Where the numbers come from</h2>
|
||||||
@@ -96,9 +96,10 @@ export default function AboutPage() {
|
|||||||
<p>
|
<p>
|
||||||
A school is not its results. The figures here describe one year group,
|
A school is not its results. The figures here describe one year group,
|
||||||
on a handful of days, measured in a way that suits national statistics
|
on a handful of days, measured in a way that suits national statistics
|
||||||
rather than your child. A small cohort makes percentages swing wildly
|
rather than your child. A small cohort makes percentages swing wildly.
|
||||||
— in a class of thirty, one pupil is more than three points. Results
|
In a class of thirty, one pupil is worth more than three points.
|
||||||
say nothing at all about whether a child will be happy somewhere.
|
Results say nothing at all about whether a child will be happy
|
||||||
|
somewhere.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -113,8 +114,8 @@ export default function AboutPage() {
|
|||||||
<h2 className={styles.subheading}>If something's wrong</h2>
|
<h2 className={styles.subheading}>If something's wrong</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Tell me and I'll fix it. Genuinely — if a figure looks wrong, or
|
Tell me and I'll fix it. If a figure looks wrong, or a page gives
|
||||||
a page gives a misleading impression of a school, I want to know.
|
a misleading impression of a school, I genuinely want to know.
|
||||||
It's the fastest way this gets better.
|
It's the fastest way this gets better.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { notFound } from 'next/navigation';
|
|||||||
import { RichText } from '@payloadcms/richtext-lexical/react';
|
import { RichText } from '@payloadcms/richtext-lexical/react';
|
||||||
import type { JSXConvertersFunction } from '@payloadcms/richtext-lexical/react';
|
import type { JSXConvertersFunction } from '@payloadcms/richtext-lexical/react';
|
||||||
import { getCachedPayload } from '@/lib/payload';
|
import { getCachedPayload } from '@/lib/payload';
|
||||||
|
import type { Post, Media } from '@/payload-types';
|
||||||
import { absoluteUrl } from '@/lib/site';
|
import { absoluteUrl } from '@/lib/site';
|
||||||
import {
|
import {
|
||||||
blogPostingJsonLd,
|
blogPostingJsonLd,
|
||||||
@@ -24,11 +25,15 @@ import styles from './Post.module.css';
|
|||||||
*/
|
*/
|
||||||
export const revalidate = 3600;
|
export const revalidate = 3600;
|
||||||
|
|
||||||
interface HeroImage {
|
/**
|
||||||
url?: string | null;
|
* heroImage is `number | Media | null`: an id when the query is shallow, the
|
||||||
alt?: string | null;
|
* populated document at depth 1. Both pages query at depth 1, but narrowing
|
||||||
width?: number | null;
|
* rather than asserting keeps it correct if that ever changes.
|
||||||
height?: number | null;
|
*/
|
||||||
|
function heroOf(post: Post): Media | null {
|
||||||
|
return typeof post.heroImage === 'object' && post.heroImage !== null
|
||||||
|
? post.heroImage
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -68,12 +73,12 @@ const findPost = cache(async (slug: string) => {
|
|||||||
return docs[0] ?? null;
|
return docs[0] ?? null;
|
||||||
});
|
});
|
||||||
|
|
||||||
function summarise(post: Record<string, unknown>) {
|
function summarise(post: Post) {
|
||||||
return {
|
return {
|
||||||
title: String(post.title),
|
title: post.title,
|
||||||
slug: String(post.slug),
|
slug: post.slug,
|
||||||
excerpt: String(post.excerpt),
|
excerpt: post.excerpt,
|
||||||
publishedAt: String(post.publishedAt),
|
publishedAt: post.publishedAt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,18 +89,18 @@ export async function generateMetadata(
|
|||||||
const post = await findPost(slug);
|
const post = await findPost(slug);
|
||||||
if (!post) return { title: 'Not found' };
|
if (!post) return { title: 'Not found' };
|
||||||
|
|
||||||
const hero = post.heroImage as HeroImage | null | undefined;
|
const hero = heroOf(post);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: String(post.title),
|
title: post.title,
|
||||||
description: String(post.excerpt),
|
description: post.excerpt,
|
||||||
alternates: { canonical: absoluteUrl(`/blog/${post.slug}`) },
|
alternates: { canonical: absoluteUrl(`/blog/${post.slug}`) },
|
||||||
openGraph: {
|
openGraph: {
|
||||||
type: 'article',
|
type: 'article',
|
||||||
title: String(post.title),
|
title: post.title,
|
||||||
description: String(post.excerpt),
|
description: post.excerpt,
|
||||||
url: absoluteUrl(`/blog/${post.slug}`),
|
url: absoluteUrl(`/blog/${post.slug}`),
|
||||||
publishedTime: String(post.publishedAt),
|
publishedTime: post.publishedAt,
|
||||||
// A post with a hero image shares that; one without falls through to the
|
// A post with a hero image shares that; one without falls through to the
|
||||||
// generated share card at app/opengraph-image.tsx.
|
// generated share card at app/opengraph-image.tsx.
|
||||||
...(hero?.url ? { images: [{ url: hero.url }] } : {}),
|
...(hero?.url ? { images: [{ url: hero.url }] } : {}),
|
||||||
@@ -110,8 +115,8 @@ export default async function PostPage(
|
|||||||
const post = await findPost(slug);
|
const post = await findPost(slug);
|
||||||
if (!post) notFound();
|
if (!post) notFound();
|
||||||
|
|
||||||
const summary = summarise(post as Record<string, unknown>);
|
const summary = summarise(post);
|
||||||
const hero = post.heroImage as HeroImage | null | undefined;
|
const hero = heroOf(post);
|
||||||
|
|
||||||
const jsonLd = {
|
const jsonLd = {
|
||||||
'@context': 'https://schema.org',
|
'@context': 'https://schema.org',
|
||||||
@@ -164,7 +169,7 @@ export default async function PostPage(
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={styles.prose}>
|
<div className={styles.prose}>
|
||||||
<RichText data={post.content as never} converters={calloutConverters} />
|
<RichText data={post.content} converters={calloutConverters} />
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ export const Callout: Block = {
|
|||||||
type: 'select',
|
type: 'select',
|
||||||
defaultValue: 'caveat',
|
defaultValue: 'caveat',
|
||||||
options: [
|
options: [
|
||||||
{ label: 'Caveat — what this does not show', value: 'caveat' },
|
{ label: 'Caveat: what this does not show', value: 'caveat' },
|
||||||
{ label: 'Note — useful aside', value: 'note' },
|
{ label: 'Note: useful aside', value: 'note' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ name: 'body', type: 'textarea', required: true },
|
{ name: 'body', type: 'textarea', required: true },
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Publishing to the blog
|
# Publishing to the blog
|
||||||
|
|
||||||
The blog is Payload CMS, running inside the Next.js app. There is no separate
|
The blog is Payload CMS, running inside the Next.js app. There is no separate
|
||||||
service and no second deploy — writing a post is done in the browser and takes
|
service and no second deploy. Writing a post is done in the browser and takes
|
||||||
effect on the live site within seconds.
|
effect on the live site within seconds.
|
||||||
|
|
||||||
## Signing in
|
## Signing in
|
||||||
|
|
||||||
`https://www.schoolcompare.co.uk/admin` — one account, no registration. If you
|
`https://www.schoolcompare.co.uk/admin`, one account, no registration. If you
|
||||||
need the account seeded on a fresh environment, run against the container:
|
need the account seeded on a fresh environment, run against the container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -24,29 +24,29 @@ password there.
|
|||||||
| Field | Notes |
|
| Field | Notes |
|
||||||
|---|---|
|
|---|---|
|
||||||
| **Title** | The `<h1>` and the browser tab. |
|
| **Title** | The `<h1>` and the browser tab. |
|
||||||
| **Slug** | The URL segment, in the sidebar. **Never change it after publishing** — it is the canonical URL, and changing it breaks every existing link and discards the page's accumulated search signal. |
|
| **Slug** | The URL segment, in the sidebar. **Never change it after publishing.** It is the canonical URL, and changing it breaks every existing link and discards the page's accumulated search signal. |
|
||||||
| **Published at** | The date shown on the post and in the feed. |
|
| **Published at** | The date shown on the post and in the feed. |
|
||||||
| **Excerpt** | Max 200 characters. Shown on the index *and* used as the meta description, so write it as a standalone sentence rather than a teaser. |
|
| **Excerpt** | Max 200 characters. Shown on the index *and* used as the meta description, so write it as a standalone sentence rather than a teaser. |
|
||||||
| **Hero image** | Optional. Becomes the social share image; without one, the site's generated card is used. |
|
| **Hero image** | Optional. Becomes the social share image; without one, the site's generated card is used. |
|
||||||
| **Content** | Rich text. `/` inserts a block. |
|
| **Content** | Rich text. `/` inserts a block. |
|
||||||
|
|
||||||
**Save as draft** while you're working — drafts are not public. **Publish** when
|
**Save as draft** while you're working; drafts are not public. **Publish** when
|
||||||
it's ready.
|
it's ready.
|
||||||
|
|
||||||
### The callout block
|
### The callout block
|
||||||
|
|
||||||
One custom block, `Callout`, with two tones:
|
One custom block, `Callout`, with two tones:
|
||||||
|
|
||||||
- **Caveat** — what a number does *not* show. This is the one that matters: it
|
- **Caveat**: what a number does *not* show. This is the one that matters. It
|
||||||
is how a post states a limitation in context rather than burying it in a
|
is how a post states a limitation in context rather than burying it in a
|
||||||
closing paragraph.
|
closing paragraph.
|
||||||
- **Note** — a useful aside.
|
- **Note**: a useful aside.
|
||||||
|
|
||||||
### Images
|
### Images
|
||||||
|
|
||||||
Every image requires alt text; the editor will not let you save without it.
|
Every image requires alt text; the editor will not let you save without it.
|
||||||
Uploads go to a Docker volume on the host, which is backed up separately from
|
Uploads go to a Docker volume on the host, which is backed up separately from
|
||||||
Postgres — an image is not reproducible from the pipeline the way school data
|
Postgres. An image is not reproducible from the pipeline the way school data
|
||||||
is.
|
is.
|
||||||
|
|
||||||
## How publishing reaches the live site
|
## How publishing reaches the live site
|
||||||
@@ -55,7 +55,7 @@ is.
|
|||||||
so a new post appears immediately.
|
so a new post appears immediately.
|
||||||
- `/blog/[slug]` is cached after its first request. Publishing or editing fires
|
- `/blog/[slug]` is cached after its first request. Publishing or editing fires
|
||||||
a `revalidatePath` from the collection's `afterChange` hook, which drops that
|
a `revalidatePath` from the collection's `afterChange` hook, which drops that
|
||||||
cached copy — so edits appear immediately too.
|
cached copy, so edits appear immediately too.
|
||||||
|
|
||||||
If a change doesn't show, it is far more likely the post is still a draft than
|
If a change doesn't show, it is far more likely the post is still a draft than
|
||||||
that the cache is stale.
|
that the cache is stale.
|
||||||
@@ -65,7 +65,7 @@ that the cache is stale.
|
|||||||
These rules are why the blog exists. A post that ignores them makes the site
|
These rules are why the blog exists. A post that ignores them makes the site
|
||||||
read more machine-generated, not less.
|
read more machine-generated, not less.
|
||||||
|
|
||||||
- **First person singular.** "I built", "I found" — never "we provide".
|
- **First person singular.** "I built", "I found", never "we provide".
|
||||||
- **Concrete over general.** "When we were looking at schools in Wandsworth"
|
- **Concrete over general.** "When we were looking at schools in Wandsworth"
|
||||||
beats any amount of stated warmth.
|
beats any amount of stated warmth.
|
||||||
- **State limits before someone else finds them.** Every post that presents a
|
- **State limits before someone else finds them.** Every post that presents a
|
||||||
@@ -73,10 +73,14 @@ read more machine-generated, not less.
|
|||||||
human wrote it: generated content does not volunteer its own weaknesses.
|
human wrote it: generated content does not volunteer its own weaknesses.
|
||||||
- **No mission statements, no "passionate about", no invented team.** There is
|
- **No mission statements, no "passionate about", no invented team.** There is
|
||||||
one person here.
|
one person here.
|
||||||
|
- **No em dashes.** They are one of the clearest tells of machine-written
|
||||||
|
prose, which is the whole problem this blog exists to fix. A full stop, a
|
||||||
|
colon, a semicolon or a pair of commas does the job and reads as though a
|
||||||
|
person chose it.
|
||||||
- **Short sentences.**
|
- **Short sentences.**
|
||||||
- **Never publish a surname, an employer, or a child's name.** The site's author
|
- **Never publish a surname, an employer, or a child's name.** The site's author
|
||||||
is "Tudor". See `/about`.
|
is "Tudor". See `/about`.
|
||||||
- **Never invent a figure**, even illustratively. On a site whose whole
|
- **Never invent a figure**, even illustratively. On a site whose whole
|
||||||
proposition is official data, a made-up number attached to a real school is
|
proposition is official data, a made-up number attached to a real school is
|
||||||
the one thing it cannot do — and no illustrative intent survives being
|
the one thing it cannot do, and no illustrative intent survives being
|
||||||
screenshotted.
|
screenshotted.
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,216 @@
|
|||||||
|
import { MigrateUpArgs, MigrateDownArgs, sql } from '@payloadcms/db-postgres'
|
||||||
|
|
||||||
|
export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {
|
||||||
|
/*
|
||||||
|
* Hand-added, and it must survive any regeneration of this file.
|
||||||
|
*
|
||||||
|
* `schemaName: 'payload'` tells Payload where to put its tables; it does not
|
||||||
|
* create the schema. Every statement below is qualified to "payload", so on
|
||||||
|
* a database that has never run this (staging and production both), the
|
||||||
|
* whole migration fails with `schema "payload" does not exist`. The schema
|
||||||
|
* only existed on the throwaway database used to generate this because it
|
||||||
|
* was created there by hand.
|
||||||
|
*/
|
||||||
|
await db.execute(sql`CREATE SCHEMA IF NOT EXISTS "payload";`)
|
||||||
|
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TYPE "payload"."enum_posts_status" AS ENUM('draft', 'published');
|
||||||
|
CREATE TYPE "payload"."enum__posts_v_version_status" AS ENUM('draft', 'published');
|
||||||
|
CREATE TABLE "payload"."users_sessions" (
|
||||||
|
"_order" integer NOT NULL,
|
||||||
|
"_parent_id" integer NOT NULL,
|
||||||
|
"id" varchar PRIMARY KEY NOT NULL,
|
||||||
|
"created_at" timestamp(3) with time zone,
|
||||||
|
"expires_at" timestamp(3) with time zone NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."users" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"display_name" varchar DEFAULT 'Tudor' NOT NULL,
|
||||||
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"email" varchar NOT NULL,
|
||||||
|
"reset_password_token" varchar,
|
||||||
|
"reset_password_expiration" timestamp(3) with time zone,
|
||||||
|
"salt" varchar,
|
||||||
|
"hash" varchar,
|
||||||
|
"login_attempts" numeric DEFAULT 0,
|
||||||
|
"lock_until" timestamp(3) with time zone
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."posts" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"title" varchar,
|
||||||
|
"slug" varchar,
|
||||||
|
"published_at" timestamp(3) with time zone,
|
||||||
|
"excerpt" varchar,
|
||||||
|
"hero_image_id" integer,
|
||||||
|
"content" jsonb,
|
||||||
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"_status" "payload"."enum_posts_status" DEFAULT 'draft'
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."_posts_v" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"parent_id" integer,
|
||||||
|
"version_title" varchar,
|
||||||
|
"version_slug" varchar,
|
||||||
|
"version_published_at" timestamp(3) with time zone,
|
||||||
|
"version_excerpt" varchar,
|
||||||
|
"version_hero_image_id" integer,
|
||||||
|
"version_content" jsonb,
|
||||||
|
"version_updated_at" timestamp(3) with time zone,
|
||||||
|
"version_created_at" timestamp(3) with time zone,
|
||||||
|
"version__status" "payload"."enum__posts_v_version_status" DEFAULT 'draft',
|
||||||
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"latest" boolean
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."media" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"alt" varchar NOT NULL,
|
||||||
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"url" varchar,
|
||||||
|
"thumbnail_u_r_l" varchar,
|
||||||
|
"filename" varchar,
|
||||||
|
"mime_type" varchar,
|
||||||
|
"filesize" numeric,
|
||||||
|
"width" numeric,
|
||||||
|
"height" numeric,
|
||||||
|
"focal_x" numeric,
|
||||||
|
"focal_y" numeric,
|
||||||
|
"sizes_thumbnail_url" varchar,
|
||||||
|
"sizes_thumbnail_width" numeric,
|
||||||
|
"sizes_thumbnail_height" numeric,
|
||||||
|
"sizes_thumbnail_mime_type" varchar,
|
||||||
|
"sizes_thumbnail_filesize" numeric,
|
||||||
|
"sizes_thumbnail_filename" varchar,
|
||||||
|
"sizes_hero_url" varchar,
|
||||||
|
"sizes_hero_width" numeric,
|
||||||
|
"sizes_hero_height" numeric,
|
||||||
|
"sizes_hero_mime_type" varchar,
|
||||||
|
"sizes_hero_filesize" numeric,
|
||||||
|
"sizes_hero_filename" varchar
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."payload_kv" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"key" varchar NOT NULL,
|
||||||
|
"data" jsonb NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."payload_locked_documents" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"global_slug" varchar,
|
||||||
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."payload_locked_documents_rels" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"order" integer,
|
||||||
|
"parent_id" integer NOT NULL,
|
||||||
|
"path" varchar NOT NULL,
|
||||||
|
"users_id" integer,
|
||||||
|
"posts_id" integer,
|
||||||
|
"media_id" integer
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."payload_preferences" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"key" varchar,
|
||||||
|
"value" jsonb,
|
||||||
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."payload_preferences_rels" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"order" integer,
|
||||||
|
"parent_id" integer NOT NULL,
|
||||||
|
"path" varchar NOT NULL,
|
||||||
|
"users_id" integer
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE "payload"."payload_migrations" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"name" varchar,
|
||||||
|
"batch" numeric,
|
||||||
|
"updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
|
||||||
|
"created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "payload"."users_sessions" ADD CONSTRAINT "users_sessions_parent_id_fk" FOREIGN KEY ("_parent_id") REFERENCES "payload"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."posts" ADD CONSTRAINT "posts_hero_image_id_media_id_fk" FOREIGN KEY ("hero_image_id") REFERENCES "payload"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."_posts_v" ADD CONSTRAINT "_posts_v_parent_id_posts_id_fk" FOREIGN KEY ("parent_id") REFERENCES "payload"."posts"("id") ON DELETE set null ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."_posts_v" ADD CONSTRAINT "_posts_v_version_hero_image_id_media_id_fk" FOREIGN KEY ("version_hero_image_id") REFERENCES "payload"."media"("id") ON DELETE set null ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "payload"."payload_locked_documents"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "payload"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_posts_fk" FOREIGN KEY ("posts_id") REFERENCES "payload"."posts"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."payload_locked_documents_rels" ADD CONSTRAINT "payload_locked_documents_rels_media_fk" FOREIGN KEY ("media_id") REFERENCES "payload"."media"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_fk" FOREIGN KEY ("parent_id") REFERENCES "payload"."payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
ALTER TABLE "payload"."payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_fk" FOREIGN KEY ("users_id") REFERENCES "payload"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
|
CREATE INDEX "users_sessions_order_idx" ON "payload"."users_sessions" USING btree ("_order");
|
||||||
|
CREATE INDEX "users_sessions_parent_id_idx" ON "payload"."users_sessions" USING btree ("_parent_id");
|
||||||
|
CREATE INDEX "users_updated_at_idx" ON "payload"."users" USING btree ("updated_at");
|
||||||
|
CREATE INDEX "users_created_at_idx" ON "payload"."users" USING btree ("created_at");
|
||||||
|
CREATE UNIQUE INDEX "users_email_idx" ON "payload"."users" USING btree ("email");
|
||||||
|
CREATE UNIQUE INDEX "posts_slug_idx" ON "payload"."posts" USING btree ("slug");
|
||||||
|
CREATE INDEX "posts_hero_image_idx" ON "payload"."posts" USING btree ("hero_image_id");
|
||||||
|
CREATE INDEX "posts_updated_at_idx" ON "payload"."posts" USING btree ("updated_at");
|
||||||
|
CREATE INDEX "posts_created_at_idx" ON "payload"."posts" USING btree ("created_at");
|
||||||
|
CREATE INDEX "posts__status_idx" ON "payload"."posts" USING btree ("_status");
|
||||||
|
CREATE INDEX "_posts_v_parent_idx" ON "payload"."_posts_v" USING btree ("parent_id");
|
||||||
|
CREATE INDEX "_posts_v_version_version_slug_idx" ON "payload"."_posts_v" USING btree ("version_slug");
|
||||||
|
CREATE INDEX "_posts_v_version_version_hero_image_idx" ON "payload"."_posts_v" USING btree ("version_hero_image_id");
|
||||||
|
CREATE INDEX "_posts_v_version_version_updated_at_idx" ON "payload"."_posts_v" USING btree ("version_updated_at");
|
||||||
|
CREATE INDEX "_posts_v_version_version_created_at_idx" ON "payload"."_posts_v" USING btree ("version_created_at");
|
||||||
|
CREATE INDEX "_posts_v_version_version__status_idx" ON "payload"."_posts_v" USING btree ("version__status");
|
||||||
|
CREATE INDEX "_posts_v_created_at_idx" ON "payload"."_posts_v" USING btree ("created_at");
|
||||||
|
CREATE INDEX "_posts_v_updated_at_idx" ON "payload"."_posts_v" USING btree ("updated_at");
|
||||||
|
CREATE INDEX "_posts_v_latest_idx" ON "payload"."_posts_v" USING btree ("latest");
|
||||||
|
CREATE INDEX "media_updated_at_idx" ON "payload"."media" USING btree ("updated_at");
|
||||||
|
CREATE INDEX "media_created_at_idx" ON "payload"."media" USING btree ("created_at");
|
||||||
|
CREATE UNIQUE INDEX "media_filename_idx" ON "payload"."media" USING btree ("filename");
|
||||||
|
CREATE INDEX "media_sizes_thumbnail_sizes_thumbnail_filename_idx" ON "payload"."media" USING btree ("sizes_thumbnail_filename");
|
||||||
|
CREATE INDEX "media_sizes_hero_sizes_hero_filename_idx" ON "payload"."media" USING btree ("sizes_hero_filename");
|
||||||
|
CREATE UNIQUE INDEX "payload_kv_key_idx" ON "payload"."payload_kv" USING btree ("key");
|
||||||
|
CREATE INDEX "payload_locked_documents_global_slug_idx" ON "payload"."payload_locked_documents" USING btree ("global_slug");
|
||||||
|
CREATE INDEX "payload_locked_documents_updated_at_idx" ON "payload"."payload_locked_documents" USING btree ("updated_at");
|
||||||
|
CREATE INDEX "payload_locked_documents_created_at_idx" ON "payload"."payload_locked_documents" USING btree ("created_at");
|
||||||
|
CREATE INDEX "payload_locked_documents_rels_order_idx" ON "payload"."payload_locked_documents_rels" USING btree ("order");
|
||||||
|
CREATE INDEX "payload_locked_documents_rels_parent_idx" ON "payload"."payload_locked_documents_rels" USING btree ("parent_id");
|
||||||
|
CREATE INDEX "payload_locked_documents_rels_path_idx" ON "payload"."payload_locked_documents_rels" USING btree ("path");
|
||||||
|
CREATE INDEX "payload_locked_documents_rels_users_id_idx" ON "payload"."payload_locked_documents_rels" USING btree ("users_id");
|
||||||
|
CREATE INDEX "payload_locked_documents_rels_posts_id_idx" ON "payload"."payload_locked_documents_rels" USING btree ("posts_id");
|
||||||
|
CREATE INDEX "payload_locked_documents_rels_media_id_idx" ON "payload"."payload_locked_documents_rels" USING btree ("media_id");
|
||||||
|
CREATE INDEX "payload_preferences_key_idx" ON "payload"."payload_preferences" USING btree ("key");
|
||||||
|
CREATE INDEX "payload_preferences_updated_at_idx" ON "payload"."payload_preferences" USING btree ("updated_at");
|
||||||
|
CREATE INDEX "payload_preferences_created_at_idx" ON "payload"."payload_preferences" USING btree ("created_at");
|
||||||
|
CREATE INDEX "payload_preferences_rels_order_idx" ON "payload"."payload_preferences_rels" USING btree ("order");
|
||||||
|
CREATE INDEX "payload_preferences_rels_parent_idx" ON "payload"."payload_preferences_rels" USING btree ("parent_id");
|
||||||
|
CREATE INDEX "payload_preferences_rels_path_idx" ON "payload"."payload_preferences_rels" USING btree ("path");
|
||||||
|
CREATE INDEX "payload_preferences_rels_users_id_idx" ON "payload"."payload_preferences_rels" USING btree ("users_id");
|
||||||
|
CREATE INDEX "payload_migrations_updated_at_idx" ON "payload"."payload_migrations" USING btree ("updated_at");
|
||||||
|
CREATE INDEX "payload_migrations_created_at_idx" ON "payload"."payload_migrations" USING btree ("created_at");`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down({ db, payload, req }: MigrateDownArgs): Promise<void> {
|
||||||
|
await db.execute(sql`
|
||||||
|
DROP TABLE "payload"."users_sessions" CASCADE;
|
||||||
|
DROP TABLE "payload"."users" CASCADE;
|
||||||
|
DROP TABLE "payload"."posts" CASCADE;
|
||||||
|
DROP TABLE "payload"."_posts_v" CASCADE;
|
||||||
|
DROP TABLE "payload"."media" CASCADE;
|
||||||
|
DROP TABLE "payload"."payload_kv" CASCADE;
|
||||||
|
DROP TABLE "payload"."payload_locked_documents" CASCADE;
|
||||||
|
DROP TABLE "payload"."payload_locked_documents_rels" CASCADE;
|
||||||
|
DROP TABLE "payload"."payload_preferences" CASCADE;
|
||||||
|
DROP TABLE "payload"."payload_preferences_rels" CASCADE;
|
||||||
|
DROP TABLE "payload"."payload_migrations" CASCADE;
|
||||||
|
DROP TYPE "payload"."enum_posts_status";
|
||||||
|
DROP TYPE "payload"."enum__posts_v_version_status";`)
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import * as migration_20260902_172826_initial from './20260902_172826_initial';
|
||||||
|
|
||||||
|
export const migrations = [
|
||||||
|
{
|
||||||
|
up: migration_20260902_172826_initial.up,
|
||||||
|
down: migration_20260902_172826_initial.down,
|
||||||
|
name: '20260902_172826_initial'
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,443 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* This file was automatically generated by Payload.
|
||||||
|
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||||
|
* and re-run `payload generate:types` to regenerate this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported timezones in IANA format.
|
||||||
|
*
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "supportedTimezones".
|
||||||
|
*/
|
||||||
|
export type SupportedTimezones =
|
||||||
|
| 'Pacific/Midway'
|
||||||
|
| 'Pacific/Niue'
|
||||||
|
| 'Pacific/Honolulu'
|
||||||
|
| 'Pacific/Rarotonga'
|
||||||
|
| 'America/Anchorage'
|
||||||
|
| 'Pacific/Gambier'
|
||||||
|
| 'America/Los_Angeles'
|
||||||
|
| 'America/Tijuana'
|
||||||
|
| 'America/Denver'
|
||||||
|
| 'America/Phoenix'
|
||||||
|
| 'America/Chicago'
|
||||||
|
| 'America/Guatemala'
|
||||||
|
| 'America/New_York'
|
||||||
|
| 'America/Bogota'
|
||||||
|
| 'America/Caracas'
|
||||||
|
| 'America/Santiago'
|
||||||
|
| 'America/Buenos_Aires'
|
||||||
|
| 'America/Sao_Paulo'
|
||||||
|
| 'Atlantic/South_Georgia'
|
||||||
|
| 'Atlantic/Azores'
|
||||||
|
| 'Atlantic/Cape_Verde'
|
||||||
|
| 'Europe/London'
|
||||||
|
| 'Europe/Berlin'
|
||||||
|
| 'Africa/Lagos'
|
||||||
|
| 'Europe/Athens'
|
||||||
|
| 'Africa/Cairo'
|
||||||
|
| 'Europe/Moscow'
|
||||||
|
| 'Asia/Riyadh'
|
||||||
|
| 'Asia/Dubai'
|
||||||
|
| 'Asia/Baku'
|
||||||
|
| 'Asia/Karachi'
|
||||||
|
| 'Asia/Tashkent'
|
||||||
|
| 'Asia/Calcutta'
|
||||||
|
| 'Asia/Dhaka'
|
||||||
|
| 'Asia/Almaty'
|
||||||
|
| 'Asia/Jakarta'
|
||||||
|
| 'Asia/Bangkok'
|
||||||
|
| 'Asia/Shanghai'
|
||||||
|
| 'Asia/Singapore'
|
||||||
|
| 'Asia/Tokyo'
|
||||||
|
| 'Asia/Seoul'
|
||||||
|
| 'Australia/Brisbane'
|
||||||
|
| 'Australia/Sydney'
|
||||||
|
| 'Pacific/Guam'
|
||||||
|
| 'Pacific/Noumea'
|
||||||
|
| 'Pacific/Auckland'
|
||||||
|
| 'Pacific/Fiji';
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
auth: {
|
||||||
|
users: UserAuthOperations;
|
||||||
|
};
|
||||||
|
blocks: {};
|
||||||
|
collections: {
|
||||||
|
users: User;
|
||||||
|
posts: Post;
|
||||||
|
media: Media;
|
||||||
|
'payload-kv': PayloadKv;
|
||||||
|
'payload-locked-documents': PayloadLockedDocument;
|
||||||
|
'payload-preferences': PayloadPreference;
|
||||||
|
'payload-migrations': PayloadMigration;
|
||||||
|
};
|
||||||
|
collectionsJoins: {};
|
||||||
|
collectionsSelect: {
|
||||||
|
users: UsersSelect<false> | UsersSelect<true>;
|
||||||
|
posts: PostsSelect<false> | PostsSelect<true>;
|
||||||
|
media: MediaSelect<false> | MediaSelect<true>;
|
||||||
|
'payload-kv': PayloadKvSelect<false> | PayloadKvSelect<true>;
|
||||||
|
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||||
|
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||||
|
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
||||||
|
};
|
||||||
|
db: {
|
||||||
|
defaultIDType: number;
|
||||||
|
};
|
||||||
|
fallbackLocale: null;
|
||||||
|
globals: {};
|
||||||
|
globalsSelect: {};
|
||||||
|
locale: null;
|
||||||
|
widgets: {
|
||||||
|
collections: CollectionsWidget;
|
||||||
|
};
|
||||||
|
user: User;
|
||||||
|
jobs: {
|
||||||
|
tasks: unknown;
|
||||||
|
workflows: unknown;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export interface UserAuthOperations {
|
||||||
|
forgotPassword: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
login: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
registerFirstUser: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
unlock: {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "users".
|
||||||
|
*/
|
||||||
|
export interface User {
|
||||||
|
id: number;
|
||||||
|
displayName: string;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
email: string;
|
||||||
|
resetPasswordToken?: string | null;
|
||||||
|
resetPasswordExpiration?: string | null;
|
||||||
|
salt?: string | null;
|
||||||
|
hash?: string | null;
|
||||||
|
loginAttempts?: number | null;
|
||||||
|
lockUntil?: string | null;
|
||||||
|
sessions?:
|
||||||
|
| {
|
||||||
|
id: string;
|
||||||
|
createdAt?: string | null;
|
||||||
|
expiresAt: string;
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
password?: string | null;
|
||||||
|
collection: 'users';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "posts".
|
||||||
|
*/
|
||||||
|
export interface Post {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
|
/**
|
||||||
|
* The URL segment. Never change it after publishing.
|
||||||
|
*/
|
||||||
|
slug: string;
|
||||||
|
publishedAt: string;
|
||||||
|
/**
|
||||||
|
* Shown on the index and used as the meta description.
|
||||||
|
*/
|
||||||
|
excerpt: string;
|
||||||
|
heroImage?: (number | null) | Media;
|
||||||
|
content: {
|
||||||
|
root: {
|
||||||
|
type: string;
|
||||||
|
children: {
|
||||||
|
type: any;
|
||||||
|
version: number;
|
||||||
|
[k: string]: unknown;
|
||||||
|
}[];
|
||||||
|
direction: ('ltr' | 'rtl') | null;
|
||||||
|
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||||
|
indent: number;
|
||||||
|
version: number;
|
||||||
|
};
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
_status?: ('draft' | 'published') | null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "media".
|
||||||
|
*/
|
||||||
|
export interface Media {
|
||||||
|
id: number;
|
||||||
|
/**
|
||||||
|
* Describe the image for screen readers.
|
||||||
|
*/
|
||||||
|
alt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
url?: string | null;
|
||||||
|
thumbnailURL?: string | null;
|
||||||
|
filename?: string | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
focalX?: number | null;
|
||||||
|
focalY?: number | null;
|
||||||
|
sizes?: {
|
||||||
|
thumbnail?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
hero?: {
|
||||||
|
url?: string | null;
|
||||||
|
width?: number | null;
|
||||||
|
height?: number | null;
|
||||||
|
mimeType?: string | null;
|
||||||
|
filesize?: number | null;
|
||||||
|
filename?: string | null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-kv".
|
||||||
|
*/
|
||||||
|
export interface PayloadKv {
|
||||||
|
id: number;
|
||||||
|
key: string;
|
||||||
|
data:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-locked-documents".
|
||||||
|
*/
|
||||||
|
export interface PayloadLockedDocument {
|
||||||
|
id: number;
|
||||||
|
document?:
|
||||||
|
| ({
|
||||||
|
relationTo: 'users';
|
||||||
|
value: number | User;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'posts';
|
||||||
|
value: number | Post;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'media';
|
||||||
|
value: number | Media;
|
||||||
|
} | null);
|
||||||
|
globalSlug?: string | null;
|
||||||
|
user: {
|
||||||
|
relationTo: 'users';
|
||||||
|
value: number | User;
|
||||||
|
};
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-preferences".
|
||||||
|
*/
|
||||||
|
export interface PayloadPreference {
|
||||||
|
id: number;
|
||||||
|
user: {
|
||||||
|
relationTo: 'users';
|
||||||
|
value: number | User;
|
||||||
|
};
|
||||||
|
key?: string | null;
|
||||||
|
value?:
|
||||||
|
| {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
| unknown[]
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-migrations".
|
||||||
|
*/
|
||||||
|
export interface PayloadMigration {
|
||||||
|
id: number;
|
||||||
|
name?: string | null;
|
||||||
|
batch?: number | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "users_select".
|
||||||
|
*/
|
||||||
|
export interface UsersSelect<T extends boolean = true> {
|
||||||
|
displayName?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
email?: T;
|
||||||
|
resetPasswordToken?: T;
|
||||||
|
resetPasswordExpiration?: T;
|
||||||
|
salt?: T;
|
||||||
|
hash?: T;
|
||||||
|
loginAttempts?: T;
|
||||||
|
lockUntil?: T;
|
||||||
|
sessions?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
id?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
expiresAt?: T;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "posts_select".
|
||||||
|
*/
|
||||||
|
export interface PostsSelect<T extends boolean = true> {
|
||||||
|
title?: T;
|
||||||
|
slug?: T;
|
||||||
|
publishedAt?: T;
|
||||||
|
excerpt?: T;
|
||||||
|
heroImage?: T;
|
||||||
|
content?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
_status?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "media_select".
|
||||||
|
*/
|
||||||
|
export interface MediaSelect<T extends boolean = true> {
|
||||||
|
alt?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
url?: T;
|
||||||
|
thumbnailURL?: T;
|
||||||
|
filename?: T;
|
||||||
|
mimeType?: T;
|
||||||
|
filesize?: T;
|
||||||
|
width?: T;
|
||||||
|
height?: T;
|
||||||
|
focalX?: T;
|
||||||
|
focalY?: T;
|
||||||
|
sizes?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
thumbnail?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
url?: T;
|
||||||
|
width?: T;
|
||||||
|
height?: T;
|
||||||
|
mimeType?: T;
|
||||||
|
filesize?: T;
|
||||||
|
filename?: T;
|
||||||
|
};
|
||||||
|
hero?:
|
||||||
|
| T
|
||||||
|
| {
|
||||||
|
url?: T;
|
||||||
|
width?: T;
|
||||||
|
height?: T;
|
||||||
|
mimeType?: T;
|
||||||
|
filesize?: T;
|
||||||
|
filename?: T;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-kv_select".
|
||||||
|
*/
|
||||||
|
export interface PayloadKvSelect<T extends boolean = true> {
|
||||||
|
key?: T;
|
||||||
|
data?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-locked-documents_select".
|
||||||
|
*/
|
||||||
|
export interface PayloadLockedDocumentsSelect<T extends boolean = true> {
|
||||||
|
document?: T;
|
||||||
|
globalSlug?: T;
|
||||||
|
user?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-preferences_select".
|
||||||
|
*/
|
||||||
|
export interface PayloadPreferencesSelect<T extends boolean = true> {
|
||||||
|
user?: T;
|
||||||
|
key?: T;
|
||||||
|
value?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "payload-migrations_select".
|
||||||
|
*/
|
||||||
|
export interface PayloadMigrationsSelect<T extends boolean = true> {
|
||||||
|
name?: T;
|
||||||
|
batch?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "collections_widget".
|
||||||
|
*/
|
||||||
|
export interface CollectionsWidget {
|
||||||
|
data?: {
|
||||||
|
[k: string]: unknown;
|
||||||
|
};
|
||||||
|
width: 'full';
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "auth".
|
||||||
|
*/
|
||||||
|
export interface Auth {
|
||||||
|
[k: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
declare module 'payload' {
|
||||||
|
export interface GeneratedTypes extends Config {}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import { Users } from '@/collections/Users';
|
|||||||
import { Posts } from '@/collections/Posts';
|
import { Posts } from '@/collections/Posts';
|
||||||
import { Media } from '@/collections/Media';
|
import { Media } from '@/collections/Media';
|
||||||
import { PAYLOAD_API_ROUTE, PAYLOAD_ADMIN_ROUTE } from '@/lib/payloadRoutes';
|
import { PAYLOAD_API_ROUTE, PAYLOAD_ADMIN_ROUTE } from '@/lib/payloadRoutes';
|
||||||
|
import { migrations } from '@/migrations';
|
||||||
|
|
||||||
const filename = fileURLToPath(import.meta.url);
|
const filename = fileURLToPath(import.meta.url);
|
||||||
const dirname = path.dirname(filename);
|
const dirname = path.dirname(filename);
|
||||||
@@ -25,8 +26,15 @@ export default buildConfig({
|
|||||||
pool: { connectionString: process.env.DATABASE_URL },
|
pool: { connectionString: process.env.DATABASE_URL },
|
||||||
// Its own schema, so no pipeline operation on `public` can reach blog
|
// Its own schema, so no pipeline operation on `public` can reach blog
|
||||||
// content. scripts/migrate_csv_to_db.py --drop lives in that blast radius,
|
// content. scripts/migrate_csv_to_db.py --drop lives in that blast radius,
|
||||||
// as does Airflow's metadata.
|
// as does Airflow's metadata. The schema itself is created by the initial
|
||||||
|
// migration: schemaName says where tables go, it does not create anything.
|
||||||
|
//
|
||||||
|
// prodMigrations runs pending migrations during server init. Without it a
|
||||||
|
// production container connects to an empty schema and fails its first
|
||||||
|
// query with 42P01 — the adapter cannot self-create tables, because
|
||||||
|
// db-postgres/connect.js gates push on NODE_ENV !== 'production'.
|
||||||
schemaName: 'payload',
|
schemaName: 'payload',
|
||||||
|
prodMigrations: migrations,
|
||||||
}),
|
}),
|
||||||
sharp,
|
sharp,
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user