beeeeg update
Some checks failed
Test and deploy staging / staging (push) Has been cancelled

This commit is contained in:
2026-09-23 04:15:10 +00:00
parent 487eff5bb2
commit d0c7b6548b
135 changed files with 9531 additions and 1777 deletions

View File

@@ -0,0 +1,69 @@
import { doublePrecision, integer, pgTable, text } from 'drizzle-orm/pg-core';
import { id, timestamps, timestamptz } from './helpers';
export const animals = pgTable('animals', {
id: id(),
species: text('species').notNull(),
breed: text('breed'),
animalName: text('animal_name'),
description: text('description'),
// AI detection stored on the animal (from the first/primary photo)
aiBreedSuggestion: text('ai_breed_suggestion'),
aiBreedConfidence: doublePrecision('ai_breed_confidence'),
// Moderation — the animal entity is moderated once.
// Accepted = visible on map (as long as it has accepted sightings too).
// Denied animals are hidden but not deleted.
submittedAt: timestamptz('submitted_at').notNull().defaultNow(),
acceptedAt: timestamptz('accepted_at'),
deniedAt: timestamptz('denied_at'),
...timestamps
});
export const sightings = pgTable('sightings', {
id: id(),
animalId: integer('animal_id')
.notNull()
.references(() => animals.id, { onDelete: 'cascade' }),
reporterName: text('reporter_name'),
seenAt: timestamptz('seen_at').notNull(),
lat: doublePrecision('lat').notNull(),
lng: doublePrecision('lng').notNull(),
submittedAt: timestamptz('submitted_at').notNull().defaultNow(),
acceptedAt: timestamptz('accepted_at'),
deniedAt: timestamptz('denied_at'),
...timestamps
});
export const photos = pgTable('photos', {
id: id(),
sightingId: integer('sighting_id')
.notNull()
.references(() => sightings.id, { onDelete: 'cascade' }),
r2Key: text('r2_key').notNull(),
url: text('url').notNull(),
sortOrder: integer('sort_order').notNull().default(0),
uploadedAt: timestamptz('uploaded_at').notNull().defaultNow(),
...timestamps
});
export type Animal = typeof animals.$inferSelect;
export type NewAnimal = typeof animals.$inferInsert;
export type Sighting = typeof sightings.$inferSelect;
export type NewSighting = typeof sightings.$inferInsert;
export type Photo = typeof photos.$inferSelect;
export type ModerationStatus = 'pending' | 'accepted' | 'denied';
export function getModerationStatus(
row: Pick<Animal | Sighting, 'acceptedAt' | 'deniedAt'>
): ModerationStatus {
if (row.deniedAt) return 'denied';
if (row.acceptedAt) return 'accepted';
return 'pending';
}