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();
});
| Column | Type | Notes |
|---|
id | bigint unsigned | Auto-incrementing primary key |
name | varchar | Display name |
email | varchar | Unique; used for login |
admin | boolean | false for caretakers, true for administrators |
email_verified_at | timestamp | Nullable; set when email is verified |
password | varchar | Bcrypt hash; hidden from serialization |
remember_token | varchar(100) | Session persistence token; hidden from serialization |
created_at | timestamp | Auto-managed by Laravel |
updated_at | timestamp | Auto-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();
});
| Column | Type | Notes |
|---|
id | bigint unsigned | Auto-incrementing primary key |
name | varchar | Enclosure display name |
limit | integer | Maximum number of animals allowed |
feeding_time | time | Scheduled feeding time for caretakers |
created_at | timestamp | Auto-managed by Laravel |
updated_at | timestamp | Auto-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();
});
| Column | Type | Notes |
|---|
id | bigint unsigned | Auto-incrementing primary key |
name | varchar | Animal’s given name |
species | varchar | Species name (e.g. “Lion”, “Giraffe”) |
is_predator | boolean | true for predators, false for herbivores |
born_at | timestamp | Date of birth; cast to datetime in Eloquent |
image_name | varchar | Nullable; original uploaded filename |
image_name_hash | varchar | Nullable; hashed filename used for storage |
enclosure_id | bigint unsigned | Nullable FK → enclosures.id |
created_at | timestamp | Auto-managed by Laravel |
updated_at | timestamp | Auto-managed by Laravel |
deleted_at | timestamp | Nullable; 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();
});
| Column | Type | Notes |
|---|
id | bigint unsigned | Auto-incrementing primary key |
user_id | bigint unsigned | FK → users.id, cascades on delete |
enclosure_id | bigint unsigned | FK → enclosures.id, cascades on delete |
created_at | timestamp | Auto-managed; recorded by withTimestamps() |
updated_at | timestamp | Auto-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.