-
Notifications
You must be signed in to change notification settings - Fork 0
Add base profile schema #68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,49 @@ | ||
| import { defineSchema } from "convex/server"; | ||
| import { defineSchema, defineTable } from "convex/server"; | ||
| import { v } from "convex/values"; | ||
|
|
||
| export default defineSchema({}); | ||
| const profileType = v.union(v.literal("person"), v.literal("community")); | ||
|
|
||
| const claimState = v.union( | ||
| v.literal("unclaimed"), | ||
| v.literal("claimed_unverified"), | ||
| v.literal("claimed_verified"), | ||
| ); | ||
|
|
||
| const publicationState = v.union( | ||
| v.literal("draft_private"), | ||
| v.literal("published"), | ||
| ); | ||
|
|
||
| const creationSource = v.union( | ||
| v.literal("self"), | ||
| v.literal("community"), | ||
| v.literal("concierge"), | ||
| v.literal("import"), | ||
| v.literal("moderator"), | ||
| ); | ||
|
|
||
| export default defineSchema({ | ||
| profiles: defineTable({ | ||
| profileType, | ||
| displayName: v.string(), | ||
| sortName: v.string(), | ||
| aliases: v.array(v.string()), | ||
| headline: v.optional(v.string()), | ||
| bio: v.optional(v.string()), | ||
| region: v.optional(v.string()), | ||
| timezone: v.optional(v.string()), | ||
| claimState, | ||
| publicationState, | ||
| creationSource, | ||
| // Mutations must set claimedAt/publishedAt with state transitions | ||
| // and patch updatedAt on every profile write. | ||
| claimedAt: v.optional(v.number()), | ||
| publishedAt: v.optional(v.number()), | ||
| updatedAt: v.number(), | ||
|
BASIC-BIT marked this conversation as resolved.
|
||
| }) | ||
| .index("by_profileType_publicationState", ["profileType", "publicationState"]) | ||
| .index("by_publicationState_claimState", ["publicationState", "claimState"]) | ||
| .index("by_claimState_profileType", ["claimState", "profileType"]) | ||
| .index("by_creationSource_claimState", ["creationSource", "claimState"]) | ||
| .index("by_profileType_sortName", ["profileType", "sortName"]), | ||
|
BASIC-BIT marked this conversation as resolved.
|
||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # Profile Schema | ||
|
|
||
| ## Status Note | ||
|
|
||
| This doc captures the first durable profile schema slice for `#9`. | ||
|
|
||
| The schema is intentionally narrow. It establishes one shared `profiles` table for people and communities without introducing slug generation, auth/account links, claim flows, permissions, normalized link tables, asset tables, search-specific indexing, or type-specific profile fields. | ||
|
|
||
| ## Locked Decisions | ||
|
|
||
| - profiles are first-class records independent from the user account that may later claim them | ||
| - `profileType` is explicit and currently supports `person` and `community` | ||
| - claim state, publication state, and creation provenance are separate fields | ||
| - community-submitted unclaimed records are represented by `creationSource: "community"` plus `claimState: "unclaimed"` | ||
| - account/user references are deferred until auth and claim issues define the account model | ||
| - slugs are deferred to `#10` | ||
| - type-aware person/community detail fields are deferred to `#11` | ||
| - normalized alias, link, asset, and rich authored block tables are deferred to later profile presentation issues | ||
|
|
||
| ## `profiles` Table | ||
|
|
||
| Core identity fields: | ||
|
|
||
| - `profileType`: `"person" | "community"` | ||
| - `displayName`: public display name | ||
| - `sortName`: normalized display-sort key for deterministic listing | ||
| - `aliases`: alternate names or searchable display variants kept inline for the first schema slice | ||
|
|
||
| Core presentation fields: | ||
|
|
||
| - `headline`: optional short label or one-line positioning statement | ||
| - `bio`: optional short public bio | ||
| - `region`: optional location or scene region text | ||
| - `timezone`: optional time zone text | ||
|
|
||
| State fields: | ||
|
|
||
| - `claimState`: `"unclaimed" | "claimed_unverified" | "claimed_verified"` | ||
| - `publicationState`: `"draft_private" | "published"` | ||
| - `creationSource`: `"self" | "community" | "concierge" | "import" | "moderator"` | ||
| - `claimedAt`: optional claim timestamp, present only after claim authority is established | ||
| - `publishedAt`: optional publication timestamp, present once a profile has been published | ||
| - `updatedAt`: application-maintained update timestamp that every profile mutation must refresh | ||
|
|
||
| Convex automatically provides `_id` and `_creationTime`; those are not duplicated in the schema. | ||
|
|
||
| ## State Semantics | ||
|
|
||
| `claimState` describes owner authority: | ||
|
|
||
| - `unclaimed`: no owner authority has been attached yet | ||
| - `claimed_unverified`: a claimant controls the profile, but stronger verification is not complete | ||
| - `claimed_verified`: owner control and verification are both established | ||
|
|
||
| `publicationState` describes public surfacing: | ||
|
|
||
| - `draft_private`: not public and not searchable | ||
| - `published`: eligible for public profile pages and later discovery flows, subject to future permission, trust, and opt-out rules | ||
|
|
||
| `creationSource` describes how the record entered the system. It is not an authority marker by itself; authority comes from `claimState` and later claim records. | ||
|
|
||
| ## Mutation Contracts | ||
|
|
||
| Convex schema validation cannot enforce conditional timestamp invariants, so profile mutations must preserve these application-level rules: | ||
|
|
||
| - set `claimedAt` when `claimState` leaves `"unclaimed"` | ||
| - set `publishedAt` when `publicationState` becomes `"published"` | ||
| - patch `updatedAt` on every profile write | ||
|
|
||
| ## Initial Indexes | ||
|
|
||
| - `by_profileType_publicationState`: public page/discovery entry points split by person vs community | ||
| - `by_publicationState_claimState`: public/trust filtering for later profile lists | ||
| - `by_claimState_profileType`: moderation and claim-review flows by claim state, with optional type splitting | ||
| - `by_creationSource_claimState`: moderation and community-submitted/unclaimed review flows | ||
| - `by_profileType_sortName`: deterministic profile listing by type | ||
|
|
||
| ## Follow-On Boundaries | ||
|
|
||
| - `#10` adds canonical slugs, validation, and uniqueness rules | ||
| - `#11` adds type-aware person/community fields and documents shared vs type-specific data | ||
| - `#12` defines read/write permission behavior | ||
| - `#13` implements claim-state transitions and trust labeling behavior | ||
| - `#22` adds presentation assets and owner-authored content sections | ||
| - `#23` adds community submission flows and source attribution details | ||
| - `#27` adds field-level visibility controls | ||
| - `#31` adds public search behavior and any search-specific indexing |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.