mirror of
https://github.com/civitai/civitai.git
synced 2026-09-20 22:08:18 +08:00
5e0949f1e9
CLAUDE.md tells agents to consult docs/features/ before implementing a feature and names eight docs. Six had not been touched since0a59df66de(2026-01-15), the single commit that created them. Auditing them against HEAD found that five were wrong on the day they were written — this is not drift, the extraction was never checked. Verified at0a59df66de: the buzz enum already read Tip=0/Fee=25; src/event-engine-common never existed; nsfwBrowsingLevelsArray already contained Blocked; the getCount procedure has no commit that ever added it; the EntityMetric enums have never had Model/Download. buzz-accounts (money severity): - Documented Tip=1 and Fee=10. Actual: Tip=0 (1 is Dues), Fee=25 (10 is Training). Both fabricated numbers name a different real transaction type, so a hardcoded literal books the wrong type with no type error and no runtime failure. Replaced the restated enum with an import-and-reference-by-name instruction. - The prize-pool example was impossible: createMultiAccountBuzzTransaction has fromAccountId min(1), so it cannot pay out of the central bank, and it omitted the required externalTransactionIdPrefix (also the refund key). Split into the real multi-account spend shape and the real createBuzzTransactionMany payout shape. - Documented 3 of 9 account types; getUserBuzzAccount described as per-type balances when it returns a one-element array defaulted to yellow. notifications (rewritten): - Led with "the notification service runs in a separate repository".927e31bfee(2026-07-01) folded it into apps/notifications + packages/civitai-notifications. The main schema now holds one notification model; the other three tables are in a separate DB the monolith cannot reach. notification-cache.ts was deleted. getCount never existed (counts are trpc.user.checkNotifications). Drawer/List had their responsibilities misattributed — the behavior is in NotificationsComposed. Rewritten around the three-way ownership table. metrics-analytics (deleted, table repointed to entity-metrics.md): - entityType:'Model'/metricType:'Download' are not in the enums (only Image, and seven metric types with no Download), so the tracking snippet never compiled. - Query snippets read raw entityMetricEvents: zero files in src/ read that table; 5 read _month and 6 read entityMetricDailyAgg_v2, with a regression test pinning it. - Documented ClickHouse Buffer tables, a pattern with zero occurrences in the repo. - entity-metrics.md already covers this ground accurately and is maintained. image-resources: - Both snippets non-compiling: fetch() returns a Record keyed by image id with resources nested one level down, not a flat array. - Detection section inverted: detected=false means inherited from Post.modelVersionId, not hand-tagged. There is no per-image tagging mutation, so the doc sent readers looking for a UI that was never built. - Added the Flipt-routed replica read (the DataPacket replica lacks the ImageResourceNew backfill), which is a live correctness trap for new queries. nsfw-filtering + bitwise-flags: - Both told you to import Flags from '~/event-engine-common/utils/nsfw-utils'. ~/ maps to src/ and that path has never existed; the real class is src/shared/utils/flags.ts (69 importers). The module they pointed at has zero importers. - nsfwBrowsingLevelsFlag documented as "R, X, or XXX"; it includes Blocked (= 60). - Raw-SQL column was nsfw_level; it is quoted camelCase "nsfwLevel". - Added what the mask alone doesn't cover: onlySelectableLevels, unrated nsfwLevel=0, and the per-domain ceiling. Bit values themselves were all correct and are kept, marked as mirroring enums.ts. Line-number citations are dropped throughout — every one had rotted. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.0 KiB
3.0 KiB
Bitwise Flag Utilities
Utilities for working with bitwise flags throughout the codebase.
Overview
The codebase uses bitwise flags extensively for:
- NSFW levels and content filtering
- Multi-select options stored efficiently (e.g.
OnboardingSteps)
Feature flags are not bitwise — those are string-keyed and Flipt-backed, see src/server/services/feature-flags.service.ts.
Key Files
| File | Purpose |
|---|---|
src/shared/utils/flags.ts |
Flags utility class |
src/server/common/enums.ts |
NsfwLevel enum (the bit values) |
src/shared/constants/browsingLevel.constants.ts |
Derived browsing-level flags + predicates |
The Flags Class
import { Flags } from '~/shared/utils/flags';
Only the four methods below are covered here; flags.ts exports about a dozen more
(toggleFlag, intersection, instanceToArray, diff, …). Read the file rather than
assuming this list is complete.
Check if Flag is Set
// Check if a specific flag is set
Flags.hasFlag(instance, flag);
// Example: Check if user has PG13 enabled
const hasPG13 = Flags.hasFlag(userBrowsingLevel, NsfwLevel.PG13);
Check for Any Overlap
// Check if ANY bits overlap between two values
Flags.intersects(a, b);
// Example: Check if content is visible to user
const isVisible = Flags.intersects(contentLevel, userBrowsingLevel);
// Returns true if content's level matches any of user's allowed levels
Add a Flag
// Add a flag to an existing value
const newValue = Flags.addFlag(instance, flag);
// Example: Add R-rated content to user's preferences
const newLevel = Flags.addFlag(userBrowsingLevel, NsfwLevel.R);
Remove a Flag
// Remove a flag from an existing value
const newValue = Flags.removeFlag(instance, flag);
// Example: Remove XXX from user's preferences
const newLevel = Flags.removeFlag(userBrowsingLevel, NsfwLevel.XXX);
Common Patterns
Combining Multiple Flags
// Combine flags with bitwise OR
const multipleFlags = Flag.A | Flag.B | Flag.C;
// Example: Allow PG, PG13, and R content
const allowedLevels = NsfwLevel.PG | NsfwLevel.PG13 | NsfwLevel.R; // = 7
Checking Multiple Conditions
// Check if ALL flags are set (bitwise AND)
const hasAll = (value & requiredFlags) === requiredFlags;
// Check if ANY flags are set (intersects)
const hasAny = Flags.intersects(value, checkFlags);
Database Queries with Flags
The column is camelCase and must be quoted in raw SQL:
-- Check if content matches user's browsing level
WHERE (i."nsfwLevel" & :userBrowsingLevel) != 0
-- Check if specific flag is set
WHERE (flags & :specificFlag) = :specificFlag
TypeScript Enum Flags
// Define flags as powers of 2
enum MyFlags {
None = 0,
OptionA = 1, // 0b0001
OptionB = 2, // 0b0010
OptionC = 4, // 0b0100
OptionD = 8, // 0b1000
All = 15, // 0b1111
}
See Also
- NSFW Filtering - Primary use case for bitwise flags