Zachary Lowden 5e8ec4f70b W13 P3b PR4 — off-site claimListing (mod-arbitrated ownership reassignment) [DARK] (#2970)
* W13 P3b PR4 — off-site claimListing (mod-arbitrated ownership reassignment) [DARK]

The FINAL P3b piece, split out of PR3. A moderator-only, arbitrated ownership
transfer for an approved OR delisted off-site AppListing: reassigns
`AppListing.userId` to a mod-verified target user, fully audited, no self-service.

Service (`offsite-moderation.service.ts`), mirroring the delist/relist/purge
tx + guard + audit pattern EXACTLY:
- kind guard: offsite-only (on-site is 1:1 with an owned AppBlock) → generic NOT_FOUND
- status guard: allow claim only on {approved, removed}; draft/pending/rejected →
  NOT_TRANSITIONABLE, zero events
- target-user validation on the PRIMARY inside the tx → friendly INVALID_TARGET_USER
  (BAD_REQUEST) instead of a raw FK 23503 leaking as INTERNAL
- pre-state (before.userId + slug) snapshotted from the in-tx PRIMARY read (mirrors
  PR3 purge) so replica lag can't stamp a stale owner
- status-guarded updateMany (status IN approved|removed); 0-count → NOT_TRANSITIONABLE,
  rollback before the audit event (zero events on a guarded/raced claim)
- ONE AppListingModerationEvent(action='claim', actor=reviewer, before/after userId, slug)
- `AppListingPublishRequest.submittedByUserId` left INTACT (locked decision — the
  historical submission record is preserved; claim reassigns the owner only)

Router: `claimListing` = moderatorProcedure + inner isModerator recheck + mapOffsiteError.
NO protectedProcedure self-claim endpoint (mod-only is the whole trust boundary).
Schema: `claimListingSchema` (appListingId, positive-int targetUserId, bounded reason).
No schema/migration change — the `claim` action already exists in the merged CHECK.

UI (dark, mods only): a Claim action on the Reports-tab action set + a modal with a
numeric target-user id + reason. View-model (`appListingModerationView`) offers claim
on approved AND removed rows.

Tests (all pass with symlinked deps): +claim service coverage (happy-path
approved/removed, status/kind/target-user guards, TOCTOU, submittedByUserId untouched,
in-tx-primary snapshot, audit correctness, reason floor); router authz (moderator-only,
tester/anon forbidden, INVALID_TARGET_USER→BAD_REQUEST, single claim proc / no self-claim);
view-model claim action-set; e2e claim guard rejections + tester-forbidden (happy path is
unit-covered — a claimable state isn't constructible in preview).

Closes P3b. Activation gate unchanged: all three P3b migrations before `release`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(w13-p3b): thread+resolve reportId on claimListing (mirror delist); render owner transfer in history

Post-audit coherence fixes for W13 P3b PR4 (claimListing):

- claimListing now accepts an optional reportId (schema, same shape/bounds as
  delist), links it on the AppListingModerationEvent, and resolves that report in
  the SAME tx — listing-scoped + status-guarded, so a mismatched/already-closed
  reportId is a silent no-op (the claim still succeeds). Mirrors delistListing
  exactly. In the impersonation flow (report -> delist -> claim -> ban) the claim
  is the substantive resolution, so it now closes the triggering report instead of
  leaving it pending. No migration: reportId column already exists (PR1).
- UI: the Claim modal (always initiated from a report row) passes report.id.
- History modal: renders the claim event's before/after owner transfer
  ("owner: X -> Y"), guarded to the {userId}-shaped claim payload so it never
  mis-reads the {status}-shaped delist/relist/purge/report-* events.
- Tests: +2 (matching reportId resolves+links; cross-listing reportId scoped
  no-op) and pin the no-report case (event reportId=null, report untouched).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 06:37:55 -05:00
2026-06-23 17:45:10 -04:00
2026-04-28 12:44:44 -06:00
2026-06-04 15:58:33 -06:00
2025-06-18 15:20:59 -04:00
2026-06-26 16:22:36 -06:00
2025-08-12 13:20:21 -04:00
2025-06-07 17:36:07 -04:00
2026-07-07 06:23:04 -05:00
2026-02-03 15:55:45 -04:00
2026-04-23 12:34:19 -06:00

Contributors Forks Stargazers Issues Apache License 2.0 Discord


Table of Contents

About the Project

Our goal with this project is to create a platform where people can share their stable diffusion models (textual inversions, hypernetworks, aesthetic gradients, VAEs, and any other crazy stuff people do to customize their AI generations), collaborate with others to improve them, and learn from each other's work. The platform allows users to create an account, upload their models, and browse models that have been shared by others. Users can also leave comments and feedback on each other's models to facilitate collaboration and knowledge sharing.

Tech Stack

We've built this project using a combination of modern web technologies, including Next.js for the frontend, TRPC for the API, and Prisma + Postgres for the database. By leveraging these tools, we've been able to create a scalable and maintainable platform that is both user-friendly and powerful.

  • DB: Prisma + Postgres
  • API: tRPC
  • Front-end + Back-end: NextJS
  • UI Kit: Mantine
  • Storage: Cloudflare

Getting Started

To get a local copy up and running, follow these steps.

Prerequisites

First, make sure that you have the following installed on your machine:

  • Docker (for running the database and services)
  • If using devcontainers
    • An IDE that supports them (VS Code with devcontainers extension, Jetbrains, etc.)
  • If running directly
    • Node.js (version 20 or later)
      • We recommend you have installed nvm in order to set the right node version to run this project
        curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
        
    • Make (optional, for easier initial setup)

Installation

  1. Follow the Prerequisites steps above
  2. Clone the repository to your local machine
  3. Choose one method:
    • a) Use devcontainers

      ⚠️ Important Warning for Windows Users: Either clone this repo onto a WSL volume, or use the "clone repository in named container volume" command. Otherwise, you will see performance issues.

      • Open the directory up in your IDE of choice
        • VS Code should prompt you to "Open in container"
          • If not, you may need to manually run Dev Containers: Open Folder in Container
        • For other IDEs, you may need to open the .devcontainer/devcontainer.json file, and click "Create devcontainer and mount sources"
        • Note: this may take some time to run initially
      • Run make run or npm run dev
    • b) Run make init
      • This command will do a few things:
        • Creates a starter env file
        • Installs npm packages
        • Spins up docker containers
        • Runs any additional database migrations
        • Creates some dummy seed data
        • Populates metrics and meilisearch
        • Initializes prisma
        • Runs the server
      • If you see an error about an app not being found, make sure node_modules/.bin is added to your path:
        • export PATH="$PATH:$(realpath node_modules/.bin)"
      • If you are an internal member, you can use the buzz and signals service
        • Set this up once by creating a personal access token in github (with read package permissions)
        • Set that to CR_PAT env
        • Run echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin
    • Please report any issues with these commands to us on discord
  4. Edit the .env.development file
    • Most default values are configured to work out of the box, except the S3 upload key and secret. To generate those, navigate to the minio web interface at http://localhost:9000 with the default username and password minioadmin, and then navigate to the "Access Keys" tab. Click "Create Access Key" and copy the generated key and secret into the .env file (S3_UPLOAD_KEY and S3_UPLOAD_SECRET, S3_IMAGE_UPLOAD_KEY and S3_IMAGE_UPLOAD_SECRET).
    • Set WEBHOOK_TOKEN to a random string of your choice. This will be used to authenticate requests to the webhook endpoint.
    • Add a random string of your choice to the email properties to allow user registration
      • EMAIL_USER
      • EMAIL_PASS
      • EMAIL_FROM (Valid email format needed)
  5. Run git submodule update --recursive
  6. Finally, visit http://localhost:3000 to see the website.

* Note that account creation will run emails through maildev, which can be accessed at http://localhost:1080.

Altering your user

  • First, create an account for yourself as you normally would through the UI.
  • You may wish to set yourself up as a moderator. To do so:
    • Use a database editor (like DataGrip) or connect directly to the DB (PGPASSWORD=postgres psql -h localhost -p 15432 -U postgres civitai)
    • Find your user (by email or username), and change isModerator to true

Known limitations

Services that require external input will currently not work locally. These include:

  • Orchestration (Generation, Training)
  • Signals (Chat, Notifications, other real-time updates)
  • Buzz

Contributing

Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!

  1. Fork the repository to your own GitHub account.
  2. Create a new branch for your changes.
  3. Make your changes to the code.
  4. Commit your changes and push the branch to your forked repository.
  5. Open a pull request on our repository.

If you would like to be more involved, consider joining the Community Development Team! For more information on the team as well as how to join, see Calling All Developers: Join Civitai's Community Development Team.

Data Migrations

Over the course of development, you may need to change the structure of the database. To do this:

  1. Make your changes to the schema.prisma file
  2. Create a folder in the prisma/migrations folder named with the convention YYYYMMDDHHmmss_brief_description_here
  3. In this folder, create a file called migration.sql
  4. In that file, put your sql changes
    • These are usually simple sql commands like ALTER TABLE ...
  5. Run make run-migrations and make gen-prisma
  6. If you are adding/changing a column or table, please try to keep the gen_seed.ts file up to date with these changes.

Sponsors

Support this project by becoming a sponsor. Your logo will show up here with a link to your website.

License

Apache License 2.0 - Please have a look at the LICENSE for more details.

S
Description
clickup: Interact with ClickUp tasks and documents - get task details, view comments, create and manage tasks, create and edit docs. Use when working with ClickUp…; quick-mockups: Create multiple UI design mockups in parallel. Use when asked to create mockups, wireframes, or design variations for a feature. Creates HTML files using…
Readme 362 MiB
Languages
TypeScript 93.3%
JavaScript 2.6%
Svelte 2.5%
PLpgSQL 0.5%
SCSS 0.4%
Other 0.6%