Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/raczkodavid/Zooniverse/llms.txt

Use this file to discover all available pages before exploring further.

Zooniverse uses four core tables to model its domain: users, enclosures, animals, and the enclosure_user pivot. All tables are managed through Laravel migrations and accessed via Eloquent models. The schema is designed for SQLite by default, though the column types used are compatible with other drivers.

Entity relationships

The three primary models relate to each other as follows:
  • Users ↔ Enclosures — many-to-many, joined through enclosure_user. A caretaker can be assigned to multiple enclosures, and an enclosure can have multiple caretakers.
  • Enclosures → Animals — one-to-many. Each enclosure hasMany animals; each animal belongsTo one enclosure.
  • Animals → Enclosure — an animal holds a nullable foreign key enclosure_id, so an animal can exist without being placed in an enclosure.

users table

Stores both administrator accounts and regular caretaker accounts. The admin flag distinguishes the two roles.
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->boolean('admin')->default(false);
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});
ColumnTypeNotes
idbigint unsignedAuto-incrementing primary key
namevarcharDisplay name
emailvarcharUnique; used for login
adminbooleanfalse for caretakers, true for administrators
email_verified_attimestampNullable; set when email is verified
passwordvarcharBcrypt hash; hidden from serialization
remember_tokenvarchar(100)Session persistence token; hidden from serialization
created_attimestampAuto-managed by Laravel
updated_attimestampAuto-managed by Laravel
Eloquent model: App\Models\User
// A user's assigned enclosures
public function enclosures(): BelongsToMany
{
    return $this->belongsToMany(Enclosure::class)->withTimestamps();
}

enclosures table

Represents a physical habitat in the zoo. Each enclosure has a maximum animal capacity and a scheduled feeding time.
Schema::create('enclosures', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->integer('limit');
    $table->time('feeding_time');
    $table->timestamps();
});
ColumnTypeNotes
idbigint unsignedAuto-incrementing primary key
namevarcharEnclosure display name
limitintegerMaximum number of animals allowed
feeding_timetimeScheduled feeding time for caretakers
created_attimestampAuto-managed by Laravel
updated_attimestampAuto-managed by Laravel
Eloquent model: App\Models\Enclosure
// Animals housed in this enclosure
public function animals(): HasMany
{
    return $this->hasMany(Animal::class);
}

// Caretakers assigned to this enclosure
public function users(): BelongsToMany
{
    return $this->belongsToMany(User::class)->withTimestamps();
}
An enclosure is considered full when animals()->count() >= limit. The isPredatorEnclosure() method returns null when the enclosure is empty (meaning both predator and herbivore animals are eligible), true when it already contains predators, and false when it contains herbivores. This prevents incompatible animals from being mixed.

animals table

Represents an individual animal. Animals carry a predator/herbivore classification, an optional photo, and a nullable foreign key to their enclosure.
Schema::create('animals', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('species');
    $table->boolean('is_predator');
    $table->timestamp('born_at');
    $table->string('image_name')->nullable();
    $table->string('image_name_hash')->nullable();
    $table->unsignedBigInteger('enclosure_id')->nullable();
    $table->foreign('enclosure_id')->references('id')->on('enclosures');
    $table->timestamps();
});

// Added in the same migration
Schema::table('animals', function (Blueprint $table) {
    $table->softDeletes();
});
ColumnTypeNotes
idbigint unsignedAuto-incrementing primary key
namevarcharAnimal’s given name
speciesvarcharSpecies name (e.g. “Lion”, “Giraffe”)
is_predatorbooleantrue for predators, false for herbivores
born_attimestampDate of birth; cast to datetime in Eloquent
image_namevarcharNullable; original uploaded filename
image_name_hashvarcharNullable; hashed filename used for storage
enclosure_idbigint unsignedNullable FK → enclosures.id
created_attimestampAuto-managed by Laravel
updated_attimestampAuto-managed by Laravel
deleted_attimestampNullable; populated on soft delete
The animals table uses Laravel’s SoftDeletes trait. Deleting an animal sets deleted_at to the current timestamp rather than removing the row. Soft-deleted animals are excluded from all standard queries but can be retrieved with Animal::withTrashed(). This allows animal records to be archived without permanent data loss.
Eloquent model: App\Models\Animal
// The enclosure this animal belongs to
public function enclosure(): BelongsTo
{
    return $this->belongsTo(Enclosure::class);
}
Attribute casts defined on the model:
protected function casts(): array
{
    return [
        'is_predator' => 'boolean',
        'born_at'     => 'datetime',
    ];
}

enclosure_user pivot table

Joins users to enclosures in a many-to-many relationship. Both foreign keys cascade on delete, so removing a user or an enclosure automatically cleans up the pivot rows.
Schema::create('enclosure_user', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('user_id');
    $table->unsignedBigInteger('enclosure_id');

    $table->foreign('user_id')
          ->references('id')->on('users')
          ->onDelete('cascade');

    $table->foreign('enclosure_id')
          ->references('id')->on('enclosures')
          ->onDelete('cascade');

    $table->timestamps();
});
ColumnTypeNotes
idbigint unsignedAuto-incrementing primary key
user_idbigint unsignedFK → users.id, cascades on delete
enclosure_idbigint unsignedFK → enclosures.id, cascades on delete
created_attimestampAuto-managed; recorded by withTimestamps()
updated_attimestampAuto-managed; recorded by withTimestamps()
Both the User and Enclosure models call withTimestamps() on the belongsToMany definition, so Laravel automatically populates created_at and updated_at on the pivot when the relationship is attached or synced.

Build docs developers (and LLMs) love