Initial commit

This commit is contained in:
fraqtal
2026-07-12 08:15:46 +00:00
commit ee0fec0691
1397 changed files with 127242 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
# AGENTS.md — core-cms
**Tag:** core-composition
**Composition-only package** that aggregates feature Payload collections and globals into a single Payload config. It does not define its own collections; instead, it imports them from feature packages.
## Responsibilities
- **Compose Payload config** — `buildConfig()` with all collections and globals from features
- **Type generation** — Output `generated-types.ts` from Payload's TypeScript generator
- **No collection definitions** — all collections owned by their respective features (`@repo/auth`, `@repo/blog`, etc.)
- **No business logic** — purely structural assembly
## Allowed imports
- **`@repo/<feature>/cms`** subpath exports only (to get collections/globals)
- e.g., `import { articles } from "@repo/blog/cms"`
- e.g., `import { users } from "@repo/auth/cms"`
- e.g., `import { pages, siteSettings } from "@repo/marketing-pages/cms"`
## Must NOT import
- Any feature's root package or other subpaths (e.g., NOT `@repo/blog/di`, NOT `@repo/blog/entities`)
- Any app package
- `@repo/core-shared`, `@repo/core-api`, `@repo/core-trpc`, `@repo/core-ui`
> Note: `@repo/core-trpc` and `@repo/core-ui` are optional packages scaffolded via `pnpm turbo gen core-package trpc` / `ui`. If not present, these constraints still apply to any future installation.
## Public exports
From `package.json`:
- `.` — the Payload config (default export) + buildConfig re-export
- `./generated-types` — Payload-generated TypeScript types
Example usage:
```typescript
import { buildConfig } from "@repo/core-cms";
// or
import type { Config, User, Article } from "@repo/core-cms/generated-types";
```
## Test conventions
- No unit tests (composition layer)
- Verify at app boot: `pnpm dev --filter @repo/cms` succeeds and admin UI loads
- Type generation: `pnpm generate:types` in `apps/cms`
## Structure
```
src/
payload.config.ts # imports feature /cms exports, calls buildConfig()
generated-types.ts # auto-generated by Payload
index.ts # re-exports config
```

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/core-eslint/base";
export default baseConfig;

View File

@@ -0,0 +1,33 @@
{
"name": "@repo/core-cms",
"private": true,
"version": "0.0.0",
"type": "module",
"exports": {
".": "./src/index.ts",
"./generated-types": "./src/generated-types.ts"
},
"scripts": {
"build": "tsc --noEmit",
"lint": "eslint .",
"typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"@repo/auth": "workspace:*",
"@repo/blog": "workspace:*",
"@repo/media": "workspace:*",
"@repo/marketing-pages": "workspace:*",
"@repo/navigation": "workspace:*",
"payload": "^3.14.0",
"@payloadcms/db-postgres": "^3.14.0",
"@payloadcms/richtext-lexical": "^3.14.0"
},
"devDependencies": {
"@repo/core-eslint": "workspace:*",
"@repo/core-testing": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@types/node": "^22.0.0",
"vitest": "^3.0.0"
}
}

View File

@@ -0,0 +1,559 @@
/* 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;
articles: Article;
pages: Page;
media: Media;
"payload-kv": PayloadKv;
"payload-locked-documents": PayloadLockedDocument;
"payload-preferences": PayloadPreference;
"payload-migrations": PayloadMigration;
};
collectionsJoins: {};
collectionsSelect: {
users: UsersSelect<false> | UsersSelect<true>;
articles: ArticlesSelect<false> | ArticlesSelect<true>;
pages: PagesSelect<false> | PagesSelect<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: {
"site-settings": SiteSetting;
header: Header;
};
globalsSelect: {
"site-settings": SiteSettingsSelect<false> | SiteSettingsSelect<true>;
header: HeaderSelect<false> | HeaderSelect<true>;
};
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 | null;
role: "admin" | "editor" | "author";
consentState?:
| {
[k: string]: unknown;
}
| unknown[]
| string
| number
| boolean
| null;
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` "articles".
*/
export interface Article {
id: number;
title: string;
/**
* Auto-generated from title if left empty
*/
slug?: string | null;
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;
} | null;
status: "draft" | "published";
author: number | User;
featuredImage?: (number | null) | Media;
publishedAt?: string | null;
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;
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;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "pages".
*/
export interface Page {
id: number;
title: string;
/**
* Auto-generated from title if left empty
*/
slug?: string | null;
hero: {
heading: string;
subheading?: string | null;
image?: (number | null) | Media;
};
layout?:
| {
title: string;
buttonLabel: string;
href: string;
id?: string | null;
blockName?: string | null;
blockType: "cta";
}[]
| null;
status: "draft" | "published";
publishedAt?: string | null;
seo: {
title: string;
description?: string | null;
};
updatedAt: string;
createdAt: string;
_status?: ("draft" | "published") | 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: "articles";
value: number | Article;
} | null)
| ({
relationTo: "pages";
value: number | Page;
} | 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;
role?: T;
consentState?: 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` "articles_select".
*/
export interface ArticlesSelect<T extends boolean = true> {
title?: T;
slug?: T;
content?: T;
status?: T;
author?: T;
featuredImage?: T;
publishedAt?: T;
updatedAt?: T;
createdAt?: T;
_status?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "pages_select".
*/
export interface PagesSelect<T extends boolean = true> {
title?: T;
slug?: T;
hero?:
| T
| {
heading?: T;
subheading?: T;
image?: T;
};
layout?:
| T
| {
cta?:
| T
| {
title?: T;
buttonLabel?: T;
href?: T;
id?: T;
blockName?: T;
};
};
status?: T;
publishedAt?: T;
seo?:
| T
| {
title?: T;
description?: 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;
}
/**
* 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` "site-settings".
*/
export interface SiteSetting {
id: number;
siteName: string;
siteDescription?: string | null;
updatedAt?: string | null;
createdAt?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "header".
*/
export interface Header {
id: number;
logo?: (number | null) | Media;
items?:
| {
label: string;
href: string;
external?: boolean | null;
id?: string | null;
}[]
| null;
updatedAt?: string | null;
createdAt?: string | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "site-settings_select".
*/
export interface SiteSettingsSelect<T extends boolean = true> {
siteName?: T;
siteDescription?: T;
updatedAt?: T;
createdAt?: T;
globalType?: T;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "header_select".
*/
export interface HeaderSelect<T extends boolean = true> {
logo?: T;
items?:
| T
| {
label?: T;
href?: T;
external?: T;
id?: T;
};
updatedAt?: T;
createdAt?: T;
globalType?: 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 {}
}

View File

@@ -0,0 +1 @@
export { default } from "./payload.config";

View File

@@ -0,0 +1,20 @@
import { describe, it, expect } from "vitest";
import config from "./payload.config";
describe("payloadConfig composition", () => {
it("registers all feature collections", async () => {
const resolved = await config;
const slugs = resolved.collections?.map((c) => c.slug) ?? [];
expect(slugs).toEqual(
expect.arrayContaining(["users", "articles", "pages", "media"]),
);
});
it("registers all feature globals", async () => {
const resolved = await config;
const slugs = resolved.globals?.map((g) => g.slug) ?? [];
expect(slugs).toEqual(
expect.arrayContaining(["site-settings", "header"]),
);
});
});

View File

@@ -0,0 +1,31 @@
import { buildConfig } from "payload";
import { postgresAdapter } from "@payloadcms/db-postgres";
import { lexicalEditor } from "@payloadcms/richtext-lexical";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { users } from "@repo/auth/cms";
import { articles } from "@repo/blog/cms";
import { media } from "@repo/media/cms";
import { pages, siteSettings } from "@repo/marketing-pages/cms";
import { header } from "@repo/navigation/cms";
const filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
export default buildConfig({
editor: lexicalEditor(),
collections: [users, articles, pages, media],
globals: [siteSettings, header],
secret: process.env.PAYLOAD_SECRET || "default-secret-change-me",
db: postgresAdapter({
pool: {
connectionString:
process.env.DATABASE_URL ||
"postgresql://postgres:postgres@localhost:5433/template",
},
}),
typescript: {
outputFile: path.resolve(dirname, "generated-types.ts"),
},
});

View File

@@ -0,0 +1,14 @@
{
"extends": "@repo/core-typescript/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": ".",
"lib": ["ES2022", "DOM"],
"types": ["vitest/globals"],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -0,0 +1,4 @@
{
"extends": ["//"],
"tags": ["core-composition"]
}

View File

@@ -0,0 +1,7 @@
import path from "node:path";
import { mergeConfig } from "vitest/config";
import { nodeVitestConfig } from "@repo/core-typescript/vitest.base.node";
export default mergeConfig(nodeVitestConfig, {
resolve: { alias: { "@": path.resolve(__dirname, "./src") } },
});