All examples

Publishing & Membership

Adapted

@fulltext, three many-to-many pairs, a subscription-billing join, and ISO currency as char(3).

7 models · Ghost (MIT)

# generate this app
$ cd examples/publishing-membership && forgedb generate all --output ./out
examples/publishing-membership/schema.forge
// Publishing CMS + membership platform — adapted from Ghost (MIT)
// Source: https://github.com/TryGhost/Ghost

// Staff users who author content; distinct from audience Members
Author {
  id: +uuid
  name: string @length(1, 150)
  slug: &^string @length(1, 191)
  email: &string @email
  bio: string?
  website: string? @url
  profile_image: string? @url
  status: string @default(active)
  created_at: +timestamp
  updated_at: timestamp?
  posts: [Post]
  roles: [Role]
}

// M2M: Role.authors <-> Author.roles — no FK between Role and Author
Role {
  id: +uuid
  name: &string @length(1, 50)
  description: string?
  created_at: +timestamp
  authors: [Author]
}

// Primary content entity: soft-deleted, fulltext-indexed content, multi-state status
Post {
  id: +uuid
  title: string @length(1, 255)
  slug: &^string @length(1, 191)
  excerpt: string?
  content: string @fulltext
  status: string @default(draft)
  visibility: string @default(public)
  featured: bool @default(false)
  published_at: timestamp?
  created_at: +timestamp
  updated_at: timestamp?
  authors: [Author]
  tags: [Tag]
  @soft_delete
  @index(status, published_at)
}

// M2M: Tag.posts <-> Post.tags — no FK between Tag and Post
Tag {
  id: +uuid
  name: string @length(1, 191)
  slug: &^string @length(1, 191)
  description: string?
  visibility: string @default(public)
  created_at: +timestamp
  posts: [Post]
}

// Audience members; distinct from staff Authors
Member {
  id: +uuid
  email: &string @email
  name: string?
  status: string @default(free)
  email_disabled: bool @default(false)
  last_seen_at: timestamp?
  created_at: +timestamp
  updated_at: timestamp?
  subscriptions: [Subscription]
}

// Paid membership tiers; prices stored as minor currency units (cents)
Tier {
  id: +uuid
  name: string @length(1, 191)
  slug: &^string @length(1, 191)
  description: string?
  tier_type: string @default(paid)
  monthly_price: i64?
  yearly_price: i64?
  currency: char(3)?
  trial_days: u32 @default(0)
  active: bool @default(true)
  created_at: +timestamp
  updated_at: timestamp?
  subscriptions: [Subscription]
}

// Explicit join model with billing payload: member + tier + billing state
Subscription {
  id: +uuid
  status: string @default(active)
  cadence: string @default(monthly)
  amount: i64
  currency: char(3)
  current_period_start: timestamp?
  current_period_end: timestamp?
  cancel_at_period_end: bool @default(false)
  created_at: +timestamp
  updated_at: timestamp?
  member: *Member
  tier: *Tier
  @index(member, status)
}

Search documentation

Find pages across the ForgeDB docs