diff --git a/README.md b/README.md
index 96294370772dd6a7ea60c7437c7c63c6f9412bb7..6be0232a3f8b924143ae4d7b56a5d0aef8aae9c7 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,6 @@ Navigate to [http://localhost:3000](http://localhost:3000)
 - Accéder à d'autre infos telle que l'API des cours sur demande à la DISI pour intégrer ça aux prédictions (ex: cours en promo complète juste implique plus d'attente)
 
 ## Coté dev
-- Ajouter une table pour les fermetures exceptionnelles
 - Protéger l'interface OpenAPI et mettre en place une interface admin pour les news et potentiellement modération (avec authentification)
 - Permettre de définir les masques proprement et de manière à pouvoir généraliser à d'autre RU
 - Accorder la charte graphique si le service est intégré à d'autres appli (bordeau/blanc service de CS, charte graphique de VR)
diff --git a/backend/db/crud.py b/backend/db/crud.py
index 1431bf2b90e4eb40405e16bc01d03ed63d560040..df872ffc41042fd3a602dcdb7dcd8fccb57b2130 100644
--- a/backend/db/crud.py
+++ b/backend/db/crud.py
@@ -18,7 +18,7 @@ from db import models, schemas
 def get_waiting_time(place: str, db: Session):
     """ Get the last estimated waiting time for the given place """
     current_date = datetime.now(tz=pytz.timezone("Europe/Paris"))
-    weekday, current_time = current_date.weekday(), current_date.time()
+    date, weekday, current_time = current_date.date(), current_date.weekday(), current_date.time()
     opening_hours = db.query(
         models.OpeningHours.open_time,
         models.OpeningHours.close_time).filter(
@@ -26,17 +26,27 @@ def get_waiting_time(place: str, db: Session):
         models.OpeningHours.day == weekday).order_by(
         models.OpeningHours.open_time).all()
     for time_slot in opening_hours:
-        if current_time < time_slot.open_time:
-            return schemas.WaitingTime(next_timetable=time_slot.open_time.strftime('%Hh%M'))
-        elif current_time <= time_slot.close_time:
-            limit = datetime.combine(date.today(), time_slot.open_time)
-            last_record = db.query(models.Records.waiting_time).filter(models.Records.place == place).filter(
-                models.Records.date >= limit).order_by(models.Records.date.desc()).first()
-            waiting_time = None
-            if last_record:
-                waiting_time = round(
-                    last_record.waiting_time.total_seconds() / 60)
-            return schemas.WaitingTime(status=True, waiting_time=waiting_time)
+        closure = db.query(
+            models.Closure).filter(
+            models.Closure.place == place,
+            models.Closure.beginning_date <= datetime.combine(date, time_slot.open_time),
+            models.Closure.end_date >= datetime.combine(date, time_slot.open_time)).order_by(
+            models.Closure.beginning_date).first()
+        if not closure:
+            if current_time < time_slot.open_time:
+                return schemas.WaitingTime(next_timetable=time_slot.open_time.strftime('%Hh%M'))
+            elif current_time <= time_slot.close_time:
+                limit = datetime.combine(date, time_slot.open_time)
+                last_record = db.query(
+                    models.Records.waiting_time).filter(
+                    models.Records.place == place).filter(
+                    models.Records.date >= limit).order_by(
+                    models.Records.date.desc()).first()
+                waiting_time = None
+                if last_record:
+                    waiting_time = round(
+                        last_record.waiting_time.total_seconds() / 60)
+                return schemas.WaitingTime(status=True, waiting_time=waiting_time)
     return schemas.WaitingTime()
 
 
@@ -46,11 +56,10 @@ def shift_time(t: time, delta: timedelta):
 
 
 def add_slot(slots_list, start_time, end_time, function):
-    average_waiting_time = function(start_time, end_time)
-    if average_waiting_time:
+    waiting_time = function(start_time, end_time)
+    if waiting_time:
         name = 60 * start_time.hour + start_time.minute
-        slots_list.append(schemas.RecordRead(
-            name=name, time=average_waiting_time))
+        slots_list.append(schemas.RecordRead(name=name, time=waiting_time))
 
 
 def get_avg_graph_points(place: str, weekday: int, min_time: time,
@@ -88,12 +97,21 @@ def get_avg_graph(place: str, db: Session):
     for the current or next available timeslot"""
     current_date = datetime.now(tz=pytz.timezone("Europe/Paris"))
     weekday, current_time = current_date.weekday(), current_date.time()
-    opening_hours = db.query(models.OpeningHours.open_time, models.OpeningHours.close_time).filter(
-        models.OpeningHours.place == place, models.OpeningHours.day == weekday).order_by(models.OpeningHours.open_time).all()
-
-    for time_slot in opening_hours:
-        if current_time <= time_slot.close_time:
-            return get_avg_graph_points(place, weekday, time_slot.open_time, time_slot.close_time, timedelta(minutes=5), db)
+    opening_hours = db.query(
+        models.OpeningHours.open_time,
+        models.OpeningHours.close_time).filter(
+        models.OpeningHours.place == place,
+        models.OpeningHours.day == weekday).order_by(
+        models.OpeningHours.open_time).all()
+    closure = db.query(
+        models.Closure).filter(
+        models.Closure.place == place,
+        models.Closure.beginning_date <= current_date,
+        models.Closure.end_date >= current_date).first()
+    if not closure:
+        for time_slot in opening_hours:
+            if current_time <= time_slot.close_time:
+                return get_avg_graph_points(place, weekday, time_slot.open_time, time_slot.close_time, timedelta(minutes=5), db)
     return []
 
 
@@ -130,18 +148,25 @@ def get_current_graph_points(place: str, current_date: date,
 def get_current_graph(place: str, db: Session):
     """ Get the waiting_time_graph for the current timeslot"""
     current_date = datetime.now(tz=pytz.timezone("Europe/Paris"))
-    weekday, day, current_time = current_date.weekday(
-    ), current_date.date(), current_date.time()
-    opening_hours = db.query(models.OpeningHours.open_time, models.OpeningHours.close_time).filter(
-        models.OpeningHours.place == place, models.OpeningHours.day == weekday).all()
-
-    for time_slot in opening_hours:
-        if time_slot.open_time <= current_time <= time_slot.close_time:
-            points = get_current_graph_points(
-                place, day, time_slot.open_time, current_time, timedelta(minutes=5), db)
-            start_time = 60 * time_slot.open_time.hour + time_slot.open_time.minute
-            end_time = 60 * time_slot.close_time.hour + time_slot.close_time.minute
-            return schemas.Graph(data=points, start=start_time, end=end_time)
+    weekday, day, current_time = current_date.weekday(), current_date.date(), current_date.time()
+    opening_hours = db.query(
+        models.OpeningHours.open_time,
+        models.OpeningHours.close_time).filter(
+        models.OpeningHours.place == place,
+        models.OpeningHours.day == weekday).all()
+    closure = db.query(
+        models.Closure).filter(
+        models.Closure.place == place,
+        models.Closure.beginning_date <= current_date,
+        models.Closure.end_date >= current_date).first()
+    if not closure:
+        for time_slot in opening_hours:
+            if time_slot.open_time <= current_time <= time_slot.close_time:
+                points = get_current_graph_points(
+                    place, day, time_slot.open_time, current_time, timedelta(minutes=5), db)
+                start_time = 60 * time_slot.open_time.hour + time_slot.open_time.minute
+                end_time = 60 * time_slot.close_time.hour + time_slot.close_time.minute
+                return schemas.Graph(data=points, start=start_time, end=end_time)
     return schemas.Graph(data=[])
 
 
@@ -155,10 +180,15 @@ def get_comments(place: str, page: int, db: Session):
             models.Comments.published_at.desc(),
             models.Comments.id.desc()).all()
     else:
-        comments = db.query(models.Comments, models.Users.username).join(models.Users).filter(models.Comments.place == place).order_by(
-            models.Comments.published_at.desc(), models.Comments.id.desc()).slice((page - 1) * 20, page * 20).all()
-    comments_list = list(schemas.Comment(
-        **comment.__dict__, username=username) for comment, username in comments)
+        comments = db.query(
+            models.Comments,
+            models.Users.username).join(
+            models.Users).filter(
+            models.Comments.place == place).order_by(
+            models.Comments.published_at.desc(),
+            models.Comments.id.desc()).slice(
+            (page - 1) * 20, page * 20).all()
+    comments_list = [schemas.Comment(**comment.__dict__, username=username) for comment, username in comments]
     comments_list.reverse()
     return comments_list
 
@@ -166,8 +196,7 @@ def get_comments(place: str, page: int, db: Session):
 def create_comment(user: schemas.User, place: str, new_comments: schemas.CommentBase, db: Session):
     """ Add a new comment to the database """
     date = datetime.now(tz=pytz.timezone("Europe/Paris"))
-    db_comment = models.Comments(
-        **new_comments.dict(), published_at=date, place=place, user_id=user.id)
+    db_comment = models.Comments(**new_comments.dict(), published_at=date, place=place, user_id=user.id)
     db.add(db_comment)
     db.commit()
     db.refresh(db_comment)
@@ -187,10 +216,43 @@ def delete_comment(id: int, db: Session):
 
 def get_news(place: str, db: Session):
     """ Get the news for the given place """
+    current_date = datetime.now(tz=pytz.timezone("Europe/Paris"))
     news = db.query(
         models.News).filter(
-        models.News.place == place).order_by(
-            models.News.published_at.desc()).all()
+        models.News.place == place,
+        models.News.end_date >= current_date).order_by(
+        models.News.published_at.desc()).all()
+    opening_hours = db.query(
+        models.OpeningHours.open_time,
+        models.OpeningHours.close_time).filter(
+        models.OpeningHours.place == place,
+        models.OpeningHours.day == current_date.weekday()).order_by(
+        models.OpeningHours.open_time).all()
+    next_timetable = None
+    for time_slot in opening_hours:
+        if current_date.time() < time_slot.open_time:
+            next_timetable=time_slot.open_time
+            break
+    if not next_timetable:
+        closure = db.query(
+            models.Closure).filter(
+            models.Closure.place == place,
+            models.Closure.beginning_date <= current_date,
+            models.Closure.end_date >= current_date).first()
+    else:
+        closure = db.query(
+            models.Closure).filter(
+            models.Closure.place == place,
+            models.Closure.beginning_date <= datetime.combine(current_date.date(), next_timetable),
+            models.Closure.end_date >= datetime.combine(current_date.date(), next_timetable)).first()
+    if closure:
+        closure_news = schemas.News(
+            title="Fermeture exceptionnelle",
+            content=f"{place} est exceptionnellement hors service jusqu'au {closure.end_date.strftime('%d/%m/%y à %Hh%M')}",
+            end_date=closure.end_date,
+            place=place,
+            published_at=closure.beginning_date)
+        news.append(closure_news)
     return news
 
 
@@ -450,3 +512,32 @@ def delete_collaborative_record(id: int, db: Session):
             models.CollaborativeRecords.id == id).delete()
     db.commit()
     return
+
+
+# Define CRUD operation for exceptional closure
+
+def get_closure(place: str, db: Session):
+    current_date = datetime.now(tz=pytz.timezone("Europe/Paris"))
+    closures = db.query(
+        models.Closure).filter(
+        models.Closure.place == place,
+        models.Closure.end_date >= current_date).order_by(
+        models.Closure.beginning_date).all()
+    return [schemas.Closure(**closure.__dict__) for closure in closures]
+
+
+def create_closure(closure: schemas.Closure, db: Session):
+    db_closure = models.Closure(**closure.dict())
+    db.add(db_closure)
+    db.commit()
+    db.refresh(db_closure)
+    return schemas.Closure(**closure.dict())
+
+
+def delete_closure(id: int, db: Session):
+    if id == 0:
+        db.query(models.Closure).delete()
+    else:
+        db.query(models.Closure).filter(models.Closure.id == id).delete()
+    db.commit()
+    return
diff --git a/backend/db/models.py b/backend/db/models.py
index cb8d31e9dfbdd5c8b88bc4e82997451656ac2885..c80580bdfbec9ff61ad427397134f7463cdc0e09 100644
--- a/backend/db/models.py
+++ b/backend/db/models.py
@@ -63,6 +63,16 @@ class OpeningHours(Base):
     close_time = Column(Time)
 
 
+class Closure(Base):
+    """ Register exceptional closure for a period sql table model """
+    __tablename__ = "closure"
+
+    id = Column(Integer, primary_key=True, index=True)
+    place = Column(String(30))
+    beginning_date = Column(DateTime)
+    end_date = Column(DateTime)
+
+
 class Users(Base):
     """ User sql table model """
     __tablename__ = "users"
diff --git a/backend/db/schemas.py b/backend/db/schemas.py
index 7eaa3d4f7474b99ebf8fbd75e6fe1a9e354cbd9f..325d2071b40bdcb8c3061058154b8d9ab1c8a74c 100644
--- a/backend/db/schemas.py
+++ b/backend/db/schemas.py
@@ -100,6 +100,21 @@ class OpeningHours(OpeningHoursBase):
         orm_mode = True
 
 
+class ClosureBase(BaseModel):
+    """ Closure schema base """
+    place: str = Field(..., title="Name of the restaurant")
+    beginning_date: datetime = Field(..., title="Beginning date of closure")
+    end_date: datetime = Field(..., title="Ending date of closure")
+
+
+class Closure(ClosureBase):
+    """ Closure schema """
+    id: int
+
+    class Config:
+        orm_mode = True
+
+
 class Restaurant(BaseModel):
     """Restaurant schema for reading"""
     name: str
diff --git a/backend/main.py b/backend/main.py
index 8b01abb83fdab29cda11a508b68a40640ae3cd56..d6c986ac7a837ba1f558c9d386bfb257ded706f8 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -1,43 +1,44 @@
-from fastapi import FastAPI
-from fastapi.middleware.cors import CORSMiddleware
-from dotenv import load_dotenv
-from threading import Thread
-import os
-
-from db import database, models
-from routers import *
-from video_capture import handle_cameras
-
-app = FastAPI(docs_url="/api/docs", openapi_url="/api/openapi.json")
-
-# load environment variables
-load_dotenv()
-
-origins = [
-    os.getenv('WEB_ROOT'),
-]
-
-app.add_middleware(
-    CORSMiddleware,
-    allow_origins=origins,
-    allow_credentials=True,
-    allow_methods=["*"],
-    allow_headers=["*"]
-)
-
-
-@app.on_event("startup")
-async def on_startup():
-    # Database creation
-    models.Base.metadata.create_all(bind=database.engine)
-    t = Thread(target=handle_cameras)
-    t.start()
-
-
-# Integration of routers
-app.include_router(stats.router)
-app.include_router(comments.router)
-app.include_router(news.router)
-app.include_router(authentication.router)
-app.include_router(websocket.router)
-app.include_router(records.router)
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
+from dotenv import load_dotenv
+from threading import Thread
+import os
+
+from db import database, models
+from routers import *
+from video_capture import handle_cameras
+
+app = FastAPI(docs_url="/api/docs", openapi_url="/api/openapi.json")
+
+# load environment variables
+load_dotenv()
+
+origins = [
+    os.getenv('WEB_ROOT'),
+]
+
+app.add_middleware(
+    CORSMiddleware,
+    allow_origins=origins,
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"]
+)
+
+
+@app.on_event("startup")
+async def on_startup():
+    # Database creation
+    models.Base.metadata.create_all(bind=database.engine)
+    t = Thread(target=handle_cameras)
+    t.start()
+
+
+# Integration of routers
+app.include_router(infos.router)
+app.include_router(records.router)
+app.include_router(stats.router)
+app.include_router(news.router)
+app.include_router(comments.router)
+app.include_router(authentication.router)
+app.include_router(websocket.router)
diff --git a/backend/routers/__init__.py b/backend/routers/__init__.py
index d88b0068a21617007209e3ba487efd5d103f01aa..ca73df7e38364f5c3193afdaa4ceae5e9b6ee649 100644
--- a/backend/routers/__init__.py
+++ b/backend/routers/__init__.py
@@ -4,3 +4,4 @@ from . import news
 from . import stats
 from . import websocket
 from . import records
+from . import infos
diff --git a/backend/routers/infos.py b/backend/routers/infos.py
new file mode 100644
index 0000000000000000000000000000000000000000..16636c4ebb80b20d5bc2d9d897e958188dd10dbe
--- /dev/null
+++ b/backend/routers/infos.py
@@ -0,0 +1,50 @@
+from fastapi import APIRouter, Depends
+from sqlalchemy.orm import Session
+from typing import List
+
+from db import schemas, crud
+from db.database import get_db
+
+
+router = APIRouter(prefix="/api", tags=["timetable"])
+
+
+# Manage opening hours
+
+@router.get('/{place}/opening_hours', response_model=List[schemas.OpeningHours])
+async def get_opening_hours(place: str, db: Session = Depends(get_db)):
+    return crud.get_opening_hours(place, db)
+
+
+@router.post('/opening_hours', response_model=schemas.OpeningHours)
+async def create_opening_hours(opening_hours: schemas.OpeningHoursBase, db: Session = Depends(get_db)):
+    return crud.create_opening_hours(opening_hours, db)
+
+
+@router.delete('/opening_hours/{id}', response_model=None)
+async def delete_opening_hours(id: int, db: Session = Depends(get_db)):
+    return crud.delete_opening_hours(id, db)
+
+
+# Manage exceptional closure
+
+@router.get('/{place}/closure', response_model=List[schemas.Closure])
+async def get_closure(place: str, db: Session = Depends(get_db)):
+    return crud.get_closure(place, db)
+
+
+@router.post('/closure', response_model=schemas.Closure)
+async def create_closure(closure: schemas.Closure, db: Session = Depends(get_db)):
+    return crud.create_closure(closure, db)
+
+
+@router.delete('/closure/{id}', response_model=None)
+async def delete_closure(id: int, db: Session = Depends(get_db)):
+    return crud.delete_closure(id, db)
+
+
+# Render restaurants infos
+
+@router.get('/restaurants', response_model=List[schemas.Restaurant])
+async def get_restaurants(db: Session = Depends(get_db)):
+    return crud.get_restaurants(db)
diff --git a/backend/routers/stats.py b/backend/routers/stats.py
index ffe229fdeffc4a85d48b24c6625e23ebdf084a8d..ec8b09e3ffe20b1b6a3edc56457e3f015e2cb475 100644
--- a/backend/routers/stats.py
+++ b/backend/routers/stats.py
@@ -1,45 +1,23 @@
 from fastapi import APIRouter, Depends
 from sqlalchemy.orm import Session
-from typing import List
 
 from db import schemas, crud
 from db.database import get_db
 
 
-router = APIRouter(prefix="/api")
+router = APIRouter(prefix="/api", tags=["stats"])
 
 
-@router.get('/{place}/waiting_time', response_model=schemas.WaitingTime, tags=["stats"])
+@router.get('/{place}/waiting_time', response_model=schemas.WaitingTime)
 async def waiting_time(place: str, db: Session = Depends(get_db)):
     return crud.get_waiting_time(place, db)
 
 
-@router.get('/{place}/stats/avg_graph', response_model=list, tags=["stats"])
+@router.get('/{place}/stats/avg_graph', response_model=list)
 async def stats(place: str, db: Session = Depends(get_db)):
     return crud.get_avg_graph(place, db)
 
 
-@router.get('/{place}/stats/current_graph', response_model=schemas.Graph, tags=["stats"])
+@router.get('/{place}/stats/current_graph', response_model=schemas.Graph)
 async def stats(place: str, db: Session = Depends(get_db)):
     return crud.get_current_graph(place, db)
-
-
-@router.get('/{place}/opening_hours',
-            response_model=List[schemas.OpeningHours], tags=["timetable"])
-async def get_opening_hours(place: str, db: Session = Depends(get_db)):
-    return crud.get_opening_hours(place, db)
-
-
-@router.post('/opening_hours', response_model=schemas.OpeningHours, tags=["timetable"])
-async def create_opening_hours(opening_hours: schemas.OpeningHoursBase, db: Session = Depends(get_db)):
-    return crud.create_opening_hours(opening_hours, db)
-
-
-@router.delete('/opening_hours/{id}', response_model=None, tags=["timetable"])
-async def delete_opening_hours(id: int, db: Session = Depends(get_db)):
-    return crud.delete_opening_hours(id, db)
-
-
-@router.get('/restaurants', response_model=List[schemas.Restaurant], tags=["timetable"])
-async def get_restaurants(db: Session = Depends(get_db)):
-    return crud.get_restaurants(db)