Terms of Service Implementation on Site
Terms of Service (Terms / Public Offer) — public agreement between service and user, defining site usage rules, rights and obligations of both parties.
Legal Status
In Russia, terms are typically structured as public offer per Articles 435-437 of the Russian Civil Code. Acceptance (acceptance) — registration, checkout, or explicit checkbox. Important: "by clicking button, you agree" is legally weaker than explicit checkbox.
Technical Implementation
Separate page with permanent URL:
Route::get('/terms', fn() => view('legal.terms'))->name('terms');
Route::get('/terms/{version}', [LegalController::class, 'termsVersion'])->name('terms.version');
Versioning:
class LegalDocument extends Model
{
protected $fillable = ['type', 'version', 'content', 'is_current', 'effective_from'];
public static function currentTerms(): self
{
return static::where('type', 'terms')
->where('is_current', true)
->firstOrFail();
}
}
Fixing acceptance version:
// On registration record accepted agreement version
$user->update([
'terms_version_accepted' => LegalDocument::currentTerms()->version,
'terms_accepted_at' => now(),
'terms_accepted_ip' => $request->ip(),
]);
Forced re-confirmation on update:
// Middleware
class RequireCurrentTerms
{
public function handle(Request $request, Closure $next)
{
$currentVersion = LegalDocument::currentTerms()->version;
if (auth()->check()
&& auth()->user()->terms_version_accepted !== $currentVersion
&& !$request->is('terms*', 'logout*', 'accept-terms')) {
return redirect()->route('terms.accept');
}
return $next($request);
}
}
Links:
{{-- In footer --}}
<a href="{{ route('terms') }}">Terms of Service</a>
{{-- On registration --}}
<label>
<input type="checkbox" name="terms_accepted" required>
I accept <a href="{{ route('terms') }}" target="_blank">terms of service</a>
</label>
Implementation Timeline
Technical part with versioning and acceptance tracking — 6–10 hours.







