user()) ->orderBy('name') ->get(['id', 'reference', 'name', 'address', 'status', 'lat', 'lng', 'updated_at']); return response()->json(['projects' => $projects]); } /** * Offline bundle for one project (Milestone 2 — minimal: structure, no media yet). */ public function bundle(Request $request, Project $project) { $user = $request->user(); abort_unless( $user->can('manage all') || $project->users()->where('user_id', $user->id)->exists(), 403 ); $project->load([ 'phases' => fn ($q) => $q->orderBy('order'), 'phases.layers', 'phases.layers.features', ]); $layers = $project->phases->flatMap->layers; $features = $layers->flatMap->features; return response()->json([ 'server_time' => now()->toIso8601String(), 'project' => [ 'id' => $project->id, 'reference' => $project->reference, 'name' => $project->name, 'address' => $project->address, 'lat' => $project->lat, 'lng' => $project->lng, 'status' => $project->status, 'updated_at' => $project->updated_at?->toIso8601String(), ], 'phases' => $project->phases->map(fn ($p) => [ 'id' => $p->id, 'name' => $p->name, 'order' => $p->order, 'color' => $p->color, 'progress_percent' => $p->progress_percent, 'updated_at' => $p->updated_at?->toIso8601String(), ])->values(), 'layers' => $layers->map(fn ($l) => [ 'id' => $l->id, 'phase_id' => $l->phase_id, 'name' => $l->name, 'color' => $l->color, 'updated_at' => $l->updated_at?->toIso8601String(), ])->values(), 'features' => $features->map(fn ($f) => [ 'id' => $f->id, 'layer_id' => $f->layer_id, 'name' => $f->name, 'geometry' => $f->geometry, 'status' => $f->status, 'progress' => $f->progress, 'updated_at' => $f->updated_at?->toIso8601String(), ])->values(), ]); } }